]> git.sur5r.net Git - glabels/blobdiff - barcode-0.98/bookland/bookland.py
Imported Upstream version 3.0.0
[glabels] / barcode-0.98 / bookland / bookland.py
diff --git a/barcode-0.98/bookland/bookland.py b/barcode-0.98/bookland/bookland.py
deleted file mode 100644 (file)
index 373587c..0000000
+++ /dev/null
@@ -1,884 +0,0 @@
-#!/usr/local/bin/python
-
-MYNAME="bookland.py"
-MYVERSION="0.92"
-COPYRIGHT="(C) 1999-2001 J. Milgram"
-DATE = "Jan. 2002"
-MAINTAINER = "bookland-bugs@cgpp.com"
-
-#   Copyright (C) 1999,2000 Judah Milgram     
-#
-#   bookland.py - generate Bookland EAN symbol for ISBN encoding
-#
-#   This program is free software; you can redistribute it and/or
-#   modify it under the terms of the GNU General Public License
-#   as published by the Free Software Foundation; either version 2
-#   of the License, or (at your option) any later version.
-#
-#   This program is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-#     
-#   You should have received a copy of the GNU General Public License along
-#   with this program; if not, write to the Free Software Foundation, Inc.,
-#   59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
-#
-# ==============================================================================
-#
-#  usage: bookland.py [ISBN] [price-code] > output.eps
-#
-#         ISBN - the ISBN, with or without check digit, with or without hyphens.
-#                default: 1-56592-197-6 ("Programming Python"). If the check digit
-#                is provided on the command line, it is verified. If not, it is
-#                calculated. It's up to you to get the hyphenation right - it's
-#                important, and something the program can't calculate for you.
-#
-#         price - the five digit add-on code. Usually used to indicate the price,
-#                 in which case the first digit indicates the currency (4=$CAN,
-#                 5=$US, etc.). The remaining digits indicate the price, with
-#                 decimal point assumed to be between the digit 3 and 4.
-#                 For example: $US 6.95 = 50695, $CAN 35.00 = 43500. Instead of a
-#                 price code, a 5 digit add-on ranging from 90000-98999 can be
-#                 used for internal purposes. BISG recommends just using 90000 if
-#                 you don't want to specify a price. Add-ons ranging from 99000 to
-#                 99999 have been reserved for special use.
-#
-#  An Encapsulated Postscript file (eps) is sent to standard out. This may in turn
-#  be converted to other formats using the pbmplus package. You may have trouble
-#  getting the OCRB to map correctly. If you already have the font, you can look in
-#  the Fontmap file to see what your system calls it, and edit the fontnames accordingly
-#  (see below). If you don't have it, you might find it on your DOS system. You
-#  need a .pfa/.pfb (Type 1) or .ttf (TrueType). Your Postscript interpreter might
-#  or might not be able to deal with TrueType. In any event, in an emergency, you
-#  might get away with Helvetica. Note that as of 1990 BISG no longer requires the
-#  ISBN to be printed in OCR-A.
-#
-#  Take the "no-warranty" disclaimer seriously. Going to print with a faulty bar
-#  can cost you a bundle, and you'll be on your own. It's up to you to verify that
-#  the symbol is valid. If you need "corporate accountability", try the Book
-#  Industry Study Group at (212) 929-1393 or the US ISBN Agency at (908) 665-6770
-#  and ask for a list of commercial vendors. Outside the US, don't know.
-#
-#  Feedback welcome. If you discover a case where the program generates a faulty
-#  symbol, I definitely want to hear about it - write me at milgram@cgpp.com or
-#  P.O. Box 8376, Langley Park, MD 20787, USA
-#
-#  INSTALLATION:
-#
-#  If you have a Python interpreter on your system, you're done. Just put this file
-#  somewhere in your path and give it execute permission. If you haven't installed
-#  Python, see http://www.python.org. It has been ported to Macs, DOS, and MS-Windows.
-#
-#  ABOUT THE BOOKLAND EAN
-#
-#  The most difficult part of this project was finding the documents that define
-#  the Bookland EAN. There appears to be no single, authoritative source that
-#  provides all the information required. Some good sources:
-#
-#  [1] "Machine-Readable Coding Guidelines for the U.S. Book Industry", Book
-#      Industry Study Group, New York, Jan., 1992. (212) 929-1393
-#  [2] "UPC Symbol Specification Manual", Uniform Code Council Inc.,
-#      Dayton, Ohio, January 1986 (May 1995 Reprint). (937) 435-3870; I found it
-#      at http://www.uc-council.org/d36-t.htm
-#  [3] "EAN Identification for Retail/Trade Items", EAN International. I found it
-#      in Feb. 1999 at http://www.ean.be/html/Numbering.html
-#  [4] "Hyphenation Instructions", web page at:
-#      http://www.isbn.org/standards/home/isbn/international/hyphenation-instructions.asp
-#
-#  The starting point of the exercise is the ISBN, assigned by the national ISBN
-#  Agency. This is a 10 digit number, the last being a check digit. The ISBN is
-#  converted to a 13 digit EAN number. The first three digits of the EAN-13 indicate
-#  the country or region. A prefix of 978 has been assigned to books, regardless
-#  of country of origin (hence, "Bookland") [3]. The remaining ten digits are the
-#  first 9 digits of the ISBN followed by the EAN-13 check digit.
-#
-#  It seems the EAN-13 check digit can be calculated using the same algorithm as the
-#  UPC Version A number. Note that the EAN-13 check digit is always between 0 and 9,
-#  compare with ISBN check digit which can range to 10 ("X"). See Reference [2],
-#  Section 2 and Appendix G for details of creation of the EAN-13 symbol. Table 2 of
-#  Appendix G provides a good comparison of the UPC-A and EAN-13 symbols.
-#
-#  The 5 digit add-on (here called, "UPC5") is defined in Ref. [2] Appendix D.
-#  The ">" to the right of the five digit code serves to enforce the "quiet zone" to
-#  the right of the bar pattern. Can't remember where I read that. It's probably
-#  optional. According to [1], in the UK, three horizontal bars appear over price
-#  add-ons. Haven't implemented that here. The UPC5 encoding is based on UPC-A and
-#  UPC-E.
-#
-#  According to [2], Section 3, the EAN-13 numbers and 5-digit add-ons are supposed
-#  to be printed in OCR-B. The ISBN itself is printed above the EAN-13 symbol. At
-#  one time it was to be printed in OCR-A, but as of 1990 this requirement has been
-#  dropped [1], and I assume this means you can use any font you like.
-#
-#  SEE ALSO:
-#
-#  "TinyHelp 5 - Making ISBN Barcodes", D. Byram-Wigfield. Another approach to making
-#                the ISBN barcode symbol. I saw it at
-#                http://www.cappella.demon.co.uk/index.html/
-#                but haven't tried it.
-#
-#  "XBarcode" - nice open-source X-Windows program for generating all sorts of bar codes.
-#               It does much more than this program, but didn't seem to do the UPC
-#               5-digit add-on or do the ISBN->EAN13 calculation (as of v. 2.11). Might
-#               have made more sense to add this capability, but I needed a Python project.
-#               In any event, their license forbids distribution in modified form!
-#
-#  HYPHENATION
-#
-#  bookland.py includes automatic hyphenation for ISBN's in group 0 and 1
-#  (English-language). This is based on my reading of Ref [4]. If in doubt,
-#  users can use the "-y" option to force the program to accept the hyphenation
-#  as input. For other ISBN groups and for ISMN's, no hyphenation is performed
-#  other than to ensure a hyphen is placed after the group identifier and before
-#  the check digit.
-#
-#  ABOUT THE ISMN:
-#
-#  See the ISMN Users' Manual, 3rd Edition, 1998, ISBN 3-88053-070-X, published by
-#  the International ISMN Agency, Staatsbibliothek Preussischer Kulturbesitz, Berlin.
-#  I found my copy at http://www.ismn.spk-berlin.de/download/ISMNmanual.pdf
-#
-#  An ISMN is just like an ISBN, except:
-#   - first character is an "M"
-#   - the "M" counts as a "3" for computing the ISMN check digit (last digit)
-#   - the checksum weights are 3,1,3,1,3,1,3,1,3, sum to be divisible by "10". This
-#     means the last character is always a numerical digit, never an "X".
-#   - the EAN number is "979" plus the *entire* ten character ISMN, except the
-#     "M" is replaced by "0". Note this means the ISMN checksum is identical to the
-#     corresponding EAN-13 checksum (excercise left to the reader).
-#
-#  When bookland.py detects an "M" in the first position of the ISBN, it interprets
-#  it as an ISMN and proceeds accordingly. The 5-digit price code symbol is suppressed.
-#
-#  BAR WIDTH REDUCTIONS
-#
-#  Starting Version 0.92, the widths of the individual bars can be reduced using the
-#  "-r" option (units are inches). This is to compensate for bleed during printing.
-#  I don't know when it's a good idea to actually use this; in any event consult with
-#  your printer first. If not input, it defaults to zero (no reduction).
-#
-#  ABOUT PYTHON
-#
-#  See http://www.python.org
-#
-#  TO DO:
-#
-#  - Generalize to more bar codes, starting with UPC-A and UPC-E. "Plain" EAN13 is
-#    already built in, could add command line argument to generate that instead of
-#    Bookland.
-#  - Make font sizes and placement easier to configure - not sure I have it right.
-#    Does human-readable 5-digit code take wider font spacing?
-#  - Clean up bounding box stuff.
-#  - Bells and whistles.
-#  - GUI?
-#
-#  HISTORY:
-#
-#  1/2002  -  v 0.92 add ISMN support (thanks to Lars-Henrik Nysten for this suggestion)
-#                    re-wrote bar generation to preclude possibility of white hairlines
-#                        between adjacent black modules. Thanks to Tero Lindfors for
-#                        reporting this bug.
-#                    new -o option to write eps to file rather than stdout
-#                    new -x option for "check only" (verifies check digit)
-#                    new -r option for bar width reduction (compensate for print bleed)
-#                    new -s option to scale module (bar) height (Lars-Henrik Nysten again)
-#                    can suppress UPC-5 price code by entering empty string. (thanks to
-#                        Jacques Du Pasquier for this suggestion)
-#                    re-wrote ISBN/ISMN sanity checks
-#                    lowercase alphas ("x" for ISBN and "m" for ISMN) now ok on input
-#                    fix "long" command line options.
-#  10/2001 -  v 0.91 add -z option for quiet zone ">"
-#                    add -f option for fonts
-#                    re-write command line parsing to use getopt
-#  1/2000  -  v 0.09 eliminate use of eval
-#  9/99    -  v 0.08 accomodate different versions of OCRB by fitting
-#                    all strings to prescribed width. Thanks to Toby Gadd
-#                    for reporting this problem and Peter Deutsch for
-#                    help finding the fix.
-#  7/99    -v0.05-0.07 improve error handling.
-#  3/27/99 - v0.04 add "--help" and "--version".
-#  3/13/99 - v0.03, do a showpage at end (it's allowed)
-#            fixed checksum calculations for certain cases
-#  2/7/99 - v0.02, fixed LH parity pattern for EAN13. It's not the check digit!
-#  2/7/99 - initial release
-# ================================================================================
-
-#
-#  barCodeSymbol - the whole printed symbol, including bar code(s) and product code(s).
-#  UPC, UPCA, UPC5, EAN13 - the number itself, with check digit, string representation,
-#                         and barcode bits
-#
-
-import re       # we should get rid of regsub and regex in favor of re
-                # hope there's no conflict.
-import string
-import sys
-import regsub
-from regex_syntax import *
-import regex
-regex.set_syntax(RE_SYNTAX_AWK)
-from types import *
-
-BooklandError = "Something wrong"
-
-
-A="A";B="B";C="C";O="O";E="E"
-UPCABITS = [{O:"0001101",E:"1110010"},
-            {O:"0011001",E:"1100110"},
-            {O:"0010011",E:"1101100"},
-            {O:"0111101",E:"1000010"},
-            {O:"0100011",E:"1011100"},
-            {O:"0110001",E:"1001110"},
-            {O:"0101111",E:"1010000"},
-            {O:"0111011",E:"1000100"},
-            {O:"0110111",E:"1001000"},
-            {O:"0001011",E:"1110100"}]
-UPCAPARITY = [ "OOOOOOEEEEEE" ] * 10
-UPCEBITS = [{O:"0001101",E:"0100111"},
-            {O:"0011001",E:"0110011"},
-            {O:"0010011",E:"0011011"},
-            {O:"0111101",E:"0100001"},
-            {O:"0100011",E:"0011101"},
-            {O:"0110001",E:"0111001"},
-            {O:"0101111",E:"0000101"},
-            {O:"0111011",E:"0010001"},
-            {O:"0110111",E:"0001001"},
-            {O:"0001011",E:"0010111"}]
-# what about UPCEPARITY? Don't need for isbn.
-UPC5BITS = UPCEBITS
-UPC5PARITY = ["EEOOO","EOEOO","EOOEO","EOOOE","OEEOO",
-              "OOEEO","OOOEE","OEOEO","OEOOE","OOEOE"]
-EAN13BITS = [{A:"0001101", B:"0100111", C:"1110010"},
-             {A:"0011001", B:"0110011", C:"1100110"},
-             {A:"0010011", B:"0011011", C:"1101100"},
-             {A:"0111101", B:"0100001", C:"1000010"},
-             {A:"0100011", B:"0011101", C:"1011100"},
-             {A:"0110001", B:"0111001", C:"1001110"},
-             {A:"0101111", B:"0000101", C:"1010000"},
-             {A:"0111011", B:"0010001", C:"1000100"},
-             {A:"0110111", B:"0001001", C:"1001000"},
-             {A:"0001011", B:"0010111", C:"1110100"}]
-EAN13PARITY = map(lambda x: x+"CCCCCC",
-                  ["AAAAAA","AABABB","AABBAB","AABBBA","ABAABB",
-                   "ABBAAB","ABBBAA","ABABAB","ABABBA","ABBABA"])
-
-PSFORMAT = "%.6f"
-# Default fonts.
-# Fonts might have a different name on your system.
-# Edit if required.
-ISBNFONT = "OCRB"      #  Doesn't have to be OCR-B
-EAN13FONT = "OCRB"
-UPC5FONT = "OCRB"
-
-class psfile:
-    
-    def __init__(self):
-        self.x0 = 100; self.y0 = 100
-        self.lines=[]
-        self.bb=[self.x0,self.y0,self.x0,self.y0]
-
-    def orbb(self,arg):
-        self.bb[0] = min(self.bb[0],self.x0+arg[0])
-        self.bb[1] = min(self.bb[1],self.y0+arg[1])
-        self.bb[2] = max(self.bb[2],self.x0+arg[2])
-        self.bb[3] = max(self.bb[3],self.y0+arg[3])
-
-    def translate(self,dx,dy):
-        self.x0 = self.x0 + dx
-        self.y0 = self.y0 + dy
-        return "%d %d translate 0 0 moveto" % (dx,dy)
-        
-    def out(self,file=None):
-        if file:
-            outfid=open(file,"w")
-        else:
-            outfid=sys.stdout
-        for line in self.lines:
-            outfid.write("%s\n"%line)
-        outfid.close()
-
-    def do(self,arg):
-        self.lines = self.lines + arg
-
-    def setbb(self):
-        for i in range(len(self.lines)):
-            if self.lines[i]=="%%BoundingBox: TBD":
-                self.lines[i]= "%%BoundingBox:" + \
-                               " %d"%self.bb[0] + \
-                               " %d"%self.bb[1] + \
-                               " %d"%self.bb[2] + \
-                               " %d"%self.bb[3]
-                return
-
-    def header(self,title,comments,ean13font,isbnfont,upc5font):
-        for i in range(len(comments)):
-            comments[i] = regsub.gsub("^","%  ",comments[i])
-        # There's a more elegant way to do the bounding box line:
-        return [ "%!PS-Adobe-2.0 EPSF-1.2",
-                 "%%Creator: " + MYNAME + "  " + MYVERSION + "  " + DATE,
-                 "%%Title: " + title,
-                 "%%BoundingBox: TBD",
-                 "%%EndComments" ] +\
-                 comments + \
-               [ "\n% These font names might be different on your system:",
-                 "/ean13font { /" + ean13font + " findfont 10 scalefont setfont } def",
-                 "/isbnfont { /" + isbnfont + " findfont 8 scalefont setfont } def",
-                 "/upc5font { /" + upc5font +" findfont 14 scalefont setfont } def\n",
-                 "/nextModule { moduleWidth 0 rmoveto } def",
-                 "% The following shenanigans is to deal with different implementations",
-                 "% of same font having different char sizes and spacing.",
-                 "% function fitstring:",
-                 "% usage: width string font fitstring",
-                 "% set font, scaled so that string exactly fits desired width",
-                 "% leave string on stack",
-                 "/fitstring { dup findfont 1 scalefont setfont % w s f",
-                 "3 1 roll % f w s",
-                 "dup stringwidth pop % f w s sw",
-                 "3 2 roll exch div % f s x",
-                 "3 2 roll findfont exch scalefont setfont",
-                 "} def",
-                 "/barHeight { 72 } def",
-                 "/nextModule { moduleWidth 0 rmoveto } def",
-                 "/topcentershow {dup stringwidth pop neg 2 div -9 rmoveto show} def",
-                 "/toprightshow {dup stringwidth pop neg -9 rmoveto show} def",
-                 "/bottomcentershow {dup stringwidth pop neg 2 div 0 rmoveto show} def",
-                 "/bottomrightshow {dup stringwidth pop neg 0 rmoveto show} def",
-                 "/W { moduleWidth mul 0 rmoveto } def",
-                 "/B { dup moduleWidth mul 2 div 0 rmoveto",
-                 "dup moduleWidth mul barWidthReduction sub setlinewidth",
-                 "0 barHeight rlineto 0 barHeight neg rmoveto",
-                 "currentpoint stroke moveto",
-                 "moduleWidth mul 2 div 0 rmoveto } def",
-                 "/L { dup moduleWidth mul 2 div 0 rmoveto",
-                 "dup moduleWidth mul barWidthReduction sub setlinewidth",
-                 "0 -5 rmoveto 0 5 rlineto",
-                 "0 barHeight rlineto 0 barHeight neg rmoveto",
-                 "currentpoint stroke moveto",
-                 "moduleWidth mul 2 div 0 rmoveto } def",
-                 self.x0,self.y0,"translate",
-                 "0 0 moveto" ]
-
-    def trailer(self):
-        return ["stroke","% showpage supposedly OK in EPS",
-                "showpage","\n% Good luck!"]
-
-        
-class UPC:
-    
-    # Includes UPC-A, UPC-E, EAN-13 (sorry), UPC-5 et al.
-
-    def __init__(self,arg):
-        # arg is a string, either:
-        # - product code including checksum
-        # - same, with hyphens (hyphens not verified)
-        # - same, but with last digit (checksum) dropped, possibly leaving a
-        #   trailing hyphen.
-        # If checksum is included, it will be verified.        
-        # N.B. "integer" representation is still a string! Just has no hyphens.
-
-        self.s=arg
-        self.verifyChars(self.s)
-        self.n = regsub.gsub("-","",self.s)    # create "integer" representation
-        self.x = self.checkDigit(self.n)       # always calculate check digit
-        if len(self.n) == self.ndigits:
-            self.verifyCheckDigit()                # if check digit given, verify it
-        elif len(self.n) == self.ndigits-1:
-            self.tackonCheckDigit()                # tack on check digit
-        else:
-            raise BooklandError, "UPC: wrong number of digits in \"" + self.s + "\""
-
-    def setbits(self,arg):                       # UPC (all)
-        self.bits=""
-        parityPattern=self.parityPattern()
-        bitchar=self.bitchar()
-        for p in range(len(arg)):
-            digit=int(arg[p])
-            # maybe better to define parityPattern with a leading blank?
-            parity=parityPattern[p]
-            bit=bitchar[digit][parity]
-            self.bits=self.bits + bit
-
-    def verifyChars(self,s):                     # UPC (all)
-        # Trailing hyphen allowed.
-        nevergood = "--|^-|[^0-9-]"
-        ierr=regex.search(nevergood,s)
-        if ierr != -1:
-            raise BooklandError, \
-                  "UPCA: in %s: illegal characters beginning with: %s" % (s,s[ierr])
-
-    def verifyCheckDigit(self):               # UPC (all)
-        # first verify correct number of digits.
-        soll=self.checkDigit(self.n)
-        ist=self.s[-1:]
-        if ist != soll:
-            raise BooklandError, "For %s checksum %s is wrong, should be %s" % \
-                             (self.s,ist,soll)
-
-    def xstring(self,p):                      # UPC (all)
-        return "%d" % p
-
-    def tackonCheckDigit(self):
-        self.n = self.n + self.x              # UPC (all)
-        self.s = self.s + self.x
-
-class UPCA(UPC):
-
-    def __init__(self,arg):
-        UPC.__init__(self,arg)
-        self.setbits(self.n[1:])                 # skip first digit
-        
-    def parityPattern(self):
-        return UPCAPARITY[int(self.x)]
-    def bitchar(self):
-        return UPCABITS
-    
-    def checkDigit(self,arg):               # UPCA/EAN13
-          weight=[1,3]*6; magic=10; sum = 0
-          for i in range(12):         # checksum based on first 12 digits.
-              sum = sum + int(arg[i]) * weight[i]
-          z = ( magic - (sum % magic) ) % magic
-          if z < 0 or z >= magic:
-              raise BooklandError, "UPC checkDigit: something wrong."
-          return self.xstring(z)
-
-
-class ISBN:
-    # Includes ISMN, if the plan falls together.
-    def __init__(self,arg):
-        self.ndigits=10            #  Includes check digit!
-        self.s=string.upper(arg)
-        self.n=re.sub("[ -]","",self.s) # "integer" representation
-        # In ISMN, I allow spaces in place of hyphens. See ISMN User's manual.
-        if re.match("^M( |-)?\d(( |-)?\d){7,7}(-| )?\d?$",self.s):
-            # ISMN
-            self.name="ISMN"
-            self.n=re.sub("^M","3",self.n)
-            self.weight=[3,1,3,1,3,1,3,1,3]
-            self.magic=10
-        elif re.match("^\d-?\d(-?\d){7,7}-?(\d|X)?$",self.s):
-            # ISBN
-            self.name="ISBN"
-            self.weight=[10,9,8,7,6,5,4,3,2]
-            self.magic=11
-        else:
-            raise BooklandError, "%s invalid (hyphenation, characters, or length)" % self.s
-        self.x = self.checkDigit()
-        if len(self.n) == self.ndigits:
-            self.verifyCheckDigit()                # if check digit given, verify it
-        elif len(self.n) == self.ndigits-1:
-            self.tackonCheckDigit()                # tack on check digit
-        else:
-            raise BooklandError, "%s failed. Please report as bug" % self.s
-
-
-    def checkDigit(self):     # ISBN and ISMN; UPCA/EAN13 similar but for weights etc.
-        # now that we're checking regex's in init, we don't have to check the
-        # argument at all. (used to check length and bad characters)
-        sum = 0
-        for i in range(9):      # checksum based on first nine digits.
-            sum = sum + int(self.n[i]) * self.weight[i]
-        z = ( self.magic - (sum % self.magic) ) % self.magic
-        if z < 0 or z >= self.magic:
-            raise BooklandError, \
-                  "%s: checksum %d is wrong - please report as bug" % (self.s,z)
-        return self.xstring(z)
-
-    def xstring(self,p):
-        if p == 10:
-            return "X"
-        else:
-            return "%d" % p
-
-    def tackonCheckDigit(self):
-        if self.s[-1:] == "-":
-            # Already have a trailing hyphen
-            self.s = self.s + self.x
-        else:
-            self.s = self.s + "-" + self.x
-
-    def verifyCheckDigit(self):               # UPC A; EAN13
-        # first verify correct number of digits.
-        soll=self.x
-        ist=self.s[-1:]
-        if ist != soll: raise BooklandError, \
-                  "For %s checksum %s is wrong, should be %s\n" % (self.s,ist,soll)
-
-class Bar:
-    # a run of adjacent modules of identical value.
-    def __init__(self,val):
-        self.val=val
-        if not self.val in "L01":
-            raise BooklandError, "bar bit: %s, pls report as a bug" % self.val
-        self.width=1
-        if self.val=="1":
-            self.color="Black"
-        elif self.val=="0":
-            self.color="White"
-        elif self.val=="L":
-            self.color="Long Black"
-    def __cmp__(self,other):
-        if self.val==other or (self.val=="L" and other=="1"):
-            return 0
-        else:
-            return 1
-    def inc(self):
-        self.width=self.width+1
-    def pslines(self):
-        if self.val=="L":
-            rval = [ "%d L " % self.width ]
-        elif self.val=="1":
-            rval = [ "%d B " % self.width ]
-        else:
-            rval = [ "%d W " % self.width ]
-        return rval
-    def __repr__(self):
-        return "%s bar of width %d" % (self.color,self.width)
-
-class barCodeSymbol:
-
-    def __init__(self):
-        self.patternWidth = len(self.bits)*self.moduleWidth
-        # Anything else?
-
-    def bitsComment(self):
-        return [ "%% Bits:\n%% %s" % self.bits ]
-        
-    def psbars(self):
-        # new version, try to prevent all hairlines between adjacent modules.
-        bars = []
-        bar=Bar(self.bits[0])
-        for bit in self.bits[1:]:
-            if bit==bar:
-                bar.inc()
-            else:
-                bars.append(bar)
-                bar=Bar(bit)
-        bars.append(bar)
-        rval = ["0 0 moveto"]
-        for bar in bars:
-            rval = rval + bar.pslines()
-        rval = rval + [ "stroke" ]
-        return rval
-
-    def psbarsold(self):
-        psbits=regsub.gsub("1","I ",self.bits)
-        psbits=regsub.gsub("0","O ",psbits)
-        psbits=regsub.gsub("L","L ",psbits)
-        linewidth=50
-        p=0; j=linewidth; m=len(psbits); psbarlines=[]; blanks="^ | $"
-        while p <= m:
-            j = min(linewidth,m-p)
-            psbarlines = psbarlines + [ regsub.gsub(blanks,"",psbits[p:p+j]) ]
-            p=p+linewidth
-        return [ "0 0 moveto" ] + psbarlines + [ "stroke" ]
-        
-    def psSetBarHeight(self):
-        return [ "/barHeight { " + PSFORMAT % self.moduleHeight + " 72 mul } def" ]
-
-    def psSetBarWidthReduction(self):
-        return [ "/barWidthReduction { " + \
-                 PSFORMAT % self.barWidthReduction + " 72 mul } def" ]
-
-    def psSetModuleWidth(self):
-        rval = [ "/moduleWidth { " + PSFORMAT % self.moduleWidth + " 72 mul } def" ]
-        return rval
-
-    def psBottomRightText(self,text,font):
-        # this is specifically for the upc5 price code.
-        # this is all starting to get messy.
-        return [ PSFORMAT % self.patternWidth + " 72 mul dup 2 div",
-                 PSFORMAT % self.moduleHeight + " 72 mul 2 add moveto",
-                 "(" + text + ") /" + font + " fitstring bottomcentershow" ]    
-
-    def psTopCenterText(self,text,font):
-        # the text at the top center of the bar pattern (i.e. the ISBN)
-        return [ PSFORMAT % self.patternWidth + " 72 mul dup 2 div",
-                 PSFORMAT % self.moduleHeight + " 72 mul 3 add moveto",
-                 " (" + text + ") /" + font  + " fitstring bottomcentershow" ]
-
-    def psFittedText(self,width,text,font):
-        return [ PSFORMAT % width + " (" + text + ") " + font + " fitstring" ]
-
-    # This is optional; serves to enforce quiet zone to right of UPC 5 add-on
-    def psGreaterThan(self,font):
-        return [ PSFORMAT % self.patternWidth + " 72 mul",
-                 PSFORMAT % self.moduleHeight + " 72 mul 2 add moveto",
-                 "/%s (>) show" % font ]
-
-class EAN13Symbol(barCodeSymbol):
-
-    def __init__(self,arg,font=EAN13FONT,heightMultiplier=1,barWidthReduction=0):
-        # arg is a string with the EAN product code
-        self.barWidthReduction=barWidthReduction
-        self.ean13 = EAN13(arg)
-        self.moduleWidth = 0.0130
-        specModuleHeight = 1.00
-        self.moduleHeight = 1.00 * heightMultiplier
-        self.bits = self.ean13.bits
-        barCodeSymbol.__init__(self)
-        self.font=font
-
-    def bb(self):
-        return  [ -12, -10, self.patternWidth*72+10, self.moduleHeight*72+12 ]
-
-    def pslines(self):
-        return self.bitsComment() + \
-               self.psSetModuleWidth() + \
-               self.psSetBarWidthReduction() + \
-               self.psSetBarHeight() + \
-               self.psbars() + \
-               self.psLRDigitLines()
-              
-    def psLRDigitLines(self):
-        # 24 = 3+6*7/2
-        # 70 = 3+6*7+4+6*7/2   "4" so we center on the "L" bars (the rightmost of
-        #      the center guard bars is an "O".
-        # "5" in check digit is the five-module spacing recommended by [2], section 3.
-        return [ "% We do the left digits first and leave the font scaled",
-                 "% as is for the 9-digit and the right-digits.",
-                 "% EAN13 Left Digits:",
-                 "moduleWidth 24 mul 0 moveto",
-                 "moduleWidth 40 mul (" + self.ean13.leftDigits + ") ",
-                 "/" + self.font + " fitstring topcentershow",
-                 "\n% EAN13 human-readable number",
-                 "% The \"9\" digit (only when encoding ISBN's and ISMN's, I think):",
-                 "-5 0 moveto (" + self.ean13.n[0] + ") toprightshow",                 
-                 "% EAN13 Right Digits:",
-                 "moduleWidth 70 mul 0 moveto",
-                 "moduleWidth 40 mul (" + self.ean13.rightDigits + ") topcentershow" ]
-
-class EAN13(UPCA):
-
-    def __init__(self,arg):
-        self.ndigits=13            #  Includes check digit!
-        UPCA.__init__(self,arg)
-        leftBits = self.bits[0:42]
-        rightBits = self.bits[42:]
-        leftGuard="L0L"
-        rightGuard="L0L"
-        center="0L0L0"
-        self.bits = leftGuard + leftBits + center + rightBits + rightGuard
-        self.leftDigits = self.n[1:7]
-        self.rightDigits = self.n[7:13]
-
-    def parityPattern(self):
-        # N.B. parity pattern based on leftmost digit, the UCC Spec calls this
-        # the "13th" digit. It's not the check digit!
-        return EAN13PARITY[int(self.n[0])]
-    def bitchar(self):
-        return EAN13BITS
-
-class UPC5Symbol(barCodeSymbol):
-
-    def __init__(self,arg,heightMultiplier=1,barWidthReduction=0):
-        # arg is a string with the 5 digit add-on.
-        self.barWidthReduction=barWidthReduction
-        self.upc5 = UPC5(arg)
-        self.moduleWidth = 0.0130
-        specModuleHeight = 0.852
-        self.moduleHeight = 0.852 * heightMultiplier
-        self.bits = self.upc5.bits
-        barCodeSymbol.__init__(self)
-
-    def pslines(self):
-        return self.bitsComment() + \
-               self.psSetModuleWidth() + \
-               self.psSetBarHeight() + \
-               self.psbars()
-
-    def bb(self):
-        # Note quiet zone is there even if we don't print the ">".
-        return  [ 0, 0, self.patternWidth*72+10, self.moduleHeight*72+10 ]
-
-UPC5Error = "Something wrong with 5-digit price code add-on."
-class UPC5(UPC):
-
-    def __init__(self,arg):
-        self.ndigits=5            #  Includes check digit!
-        p=re.search("[^0-9]",arg)
-        if p:
-          badchar=arg[p.start()]
-          raise UPC5Error, "\"%s\" is wrong. The character \"%s\" is not allowed. Price code add-on should contain %d digits and nothing else. Or leave blank to suppress the UPC-5 code." % (arg,badchar,self.ndigits)
-        elif len(arg) != self.ndigits:
-          raise UPC5Error, \
-            "\"%s\" is wrong. Price code add-on should have exactly %d digits." % (arg,self.ndigits)
-        UPC.__init__(self,arg)
-        self.setbits(self.n)
-        leftGuard="1011"
-        # no right guard for UPC 5-digit add-on
-        # Have to insert pesky delineators:
-        delineator = "01"
-        self.bits = leftGuard + \
-                    self.bits[0:7] + delineator + \
-                    self.bits[7:14] + delineator + \
-                    self.bits[14:21] + delineator + \
-                    self.bits[21:28] + delineator + \
-                    self.bits[28:35]
-
-    def checkDigit(self,arg):     # UPC5
-          weight=[3,9,3,9,3]; sum = 0
-          for i in range(5):
-              sum = sum + int(arg[i]) * weight[i]
-          return self.xstring(sum % 10)
-
-    def verifyCheckDigit(self):               # UPC2/5 checksum not in number
-        return
-
-    def parityPattern(self):
-        return UPC5PARITY[int(self.x)]
-    def bitchar(self):
-        return UPC5BITS
-
-class bookland(barCodeSymbol):
-
-    def __init__(self,isbn,price="",*rest):
-
-
-        # Some defaults:
-        ean13font=EAN13FONT
-        isbnfont=ISBNFONT
-        upc5font = UPC5FONT
-        zone=None
-        heightMultiplier=1.0
-        commandLine=""
-        barWidthReduction=0
-
-        # Maybe different fonts:
-        if len(rest)>0:
-            font=rest[0]
-            if font:
-                ean13font=font
-                isbnfont=font
-                upc5font=font
-        if len(rest)>1:
-            zone=rest[1]
-        if len(rest)>2:
-            heightMultiplier=float(rest[2])
-        if len(rest) > 3:
-            commandLine=rest[3]
-        if len(rest) > 4:
-            barWidthReduction=float(rest[4])
-
-        # Initial setup:
-        
-        self.ps = psfile()
-        self.isbn = ISBN(isbn)
-
-        # Header, EAN13 bars, EAN13 number, and ISBN:
-
-        if self.isbn.name=="ISMN":
-            self.ean13Symbol = EAN13Symbol("9790"+self.isbn.n[1:9],ean13font,heightMultiplier,barWidthReduction)
-        elif self.isbn.name=="ISBN":
-            self.ean13Symbol = EAN13Symbol("978"+self.isbn.n[:9],ean13font,heightMultiplier,barWidthReduction)
-        else:
-            raise BooklandError, "Internal error doing %s, please report as bug" % isbn
-
-        self.ps.orbb(self.ean13Symbol.bb())
-        comments = ["",
-                    "     This is free software and comes with NO WARRANTY WHATSOVER",
-                    "     Think twice before going to press with this bar code!",
-                    "",
-                    "Command line: %s" % commandLine,
-                    "" ]
-        self.ps.lines = self.ps.header(self.isbn.s,comments,ean13font,isbnfont,upc5font) + \
-                        [ "ean13font" ] + \
-                        self.ean13Symbol.pslines() +\
-                        [ "isbnfont" ] + \
-                        self.ean13Symbol.psTopCenterText("%s %s" % (self.isbn.name,self.isbn.s),isbnfont)
-
-        # 5-digit add-on:  (optional for ISBN only)
-        BLANK=re.compile("^ *$")
-        if self.isbn.name=="ISBN" and not BLANK.match(price):
-            # 105 = 95 + 10; 10 = separation (min is 9)        
-            translate=[ self.ps.translate( self.ean13Symbol.moduleWidth * 72 * 105, 0 ) ]
-            self.upc5Symbol = UPC5Symbol(price,heightMultiplier,barWidthReduction)
-            self.ps.orbb(self.upc5Symbol.bb())
-            self.ps.lines = self.ps.lines + \
-                            translate + \
-                            self.upc5Symbol.pslines() + \
-                            [ "upc5font" ] +\
-                            self.upc5Symbol.psBottomRightText(price,upc5font)
-            if zone: self.ps.lines=self.ps.lines + self.upc5Symbol.psGreaterThan(upc5font)
-        else:
-            self.ps.lines.append("%% Skipping UPC-5 price code symbol per request")
-
-        self.ps.lines=self.ps.lines + self.ps.trailer()
-
-        # Can now set bounding box.
-
-        self.ps.setbb()
-    
-# Here we go ...
-        
-if __name__ == '__main__':
-
-    def printUsage():
-        print "Usage: bookland [-h|--help] [-v|--version] [-x|--check] [-f|--font=<font>] [-s|--height=<height scale>] [-r|--reduction=<reduction factor>] [-o|outfile=<filename>] [-z|--quietzone] [<isbn>|<isbn> <price>]"
-        print "Report bugs to " + MAINTAINER
-
-    def printVersion():
-        sys.stderr.write("%s version %s %s.\n" % (MYNAME,MYVERSION,COPYRIGHT))
-        sys.stderr.write("Bugs to %s\n" % MAINTAINER)
-        sys.stderr.write("This is free software and comes with NO WARRANTY\n")
-
-    import getopt
-    try:
-        opts,args = getopt.getopt(sys.argv[1:],
-                                  "xr:s:uvf:hzo:",
-                                  ["reduction=","outfile=","height=","noupc",
-                                   "check","version","help","font=","quietzone"])
-    except:
-        printUsage()
-        sys.exit(0)
-
-    # some initial defaults:
-    isbn = "1-56592-197-6" # Mark Lutz, "Programming Python",
-                           # O'Reilly, Sebastopol CA, 1996
-    price = "90000"
-    font=None
-    zone=None
-    checkonly=None
-    outfile=None
-    heightMultiplier=1
-    commandLine = string.join(sys.argv)
-    barWidthReduction = 0
-
-    # parse command line:
-    for opt,val in opts:
-        if opt in ("-v","--version"):
-            printVersion()
-            sys.exit(0)
-        elif opt in ("-h","--help"):
-            printUsage()
-            sys.exit(0)
-        elif opt in ("-f","--font"):
-            font=val
-        elif opt in ("-z","--quietzone"):
-            zone=1
-        elif opt in ("-x","--check"):
-            checkonly=1
-        elif opt in ("-s","--height"):
-            heightMultiplier = float(val)
-        elif opt in ("-r","--reduction"):
-            barWidthReduction = val
-        elif opt in ("-o","--outfile"):
-            outfile=val
-    if len(args)==1:
-        isbn=args[0]
-    elif len(args)==2:
-        isbn=args[0]
-        price=args[1]
-
-    # Do stuff.
-
-    printVersion()
-    try:
-        b = bookland(isbn,price,font,zone,heightMultiplier,
-                     commandLine,barWidthReduction)
-        if not checkonly: b.ps.out(outfile)
-        if outfile:
-            sys.stderr.write("Output written to %s\n" % outfile)
-    except BooklandError, message:
-        sys.stderr.write(BooklandError + ": " + message + "\n")
-        sys.exit(1)