BarCode128

From Pickwiki
Jump to navigationJump to search

Bill,

Wow, it looks like I started a small war here. That wasn't my intent - well, maybe a little, just to keep the blood pumping. I am putting the source at the end of this email, as some people don't or can't receive attachments. It's not too long. If you, or anyone else, knows how, please feel free to post it on the U2 wiki and/or Pickwiki. Post it anywhere else you'd like. Use it, share it, modify it to make it better, just share your improvements with me and don't claim it as your own. I've also done code 39, Codabar, int25 and Postnet. I haven't done codes like UPC because I didn't have a need for them. With the algorithms, I'd be glad to, just for the pleasure of doing it. And yes, I'm a Linux geek. I heartily approve of sharing knowledge, information and source code, as long as it doesn't violate someone's license or copyright. I have to express my gratitude here to Tony for QSORT. We use it a lot, and credit Tony as author.

[Excuse me for a minute, my mouse cursor just took off by itself across the screen while I was typing, and I had to see how far it would go. It crawled slowly to the left of the screen and just sat there. Spooky!!!]

It looks like Print Wizard does a whole lot more than just barcodes, and is certainly worth a serious look. I will be looking at it, and don't mind buying software that's genuinely useful to me.

This barcode routine can be used as is or adapted easily for pretty much any MV system. I've used it in Universe, Unidata, Advanced Pick, and most recently, Jbase. Since it is an MV Basic program and outputs simple escape codes, it can be used on Unix, AIX (our platform), Linux or Windows.

All the best to all who have participated in this discussion, especially Bob Rasmussen, who is a gentleman of the first order, and a hell of a developer.

Charlie

Here's the source. It may wrap a little, but should straighten out if you paste it into a wider screen. Brackets (]) in a string are probably literal value marks. Have fun!

  SUBROUTINE PRINT.BARCODE.128.HP.SUB (MESSAGE, INDENT, BAR.WIDTH, BAR.HEIGHT, ORIENTATION, PASSED.PARAMS)
  * Title:        PRINT.BARCODE.128.HP.SUB
  * Written by:   Charlie Noah
  * Date written: 1988
  * Print barcode in Code 128 on HP Laserjet printers
  *" (C) Copyright 1988 Charles W. Noah Associates"
  ****************************************
  *
  * Rev 02-19-2010 12:50 by:    40 charlien charlien     350 lines;  13,149 bytes  5,271,091,321
  *
  * Start modification history
  * Mod 02 02-16-2010 CWN Modify Mod 01 to make all barcode routines consistent SMURF AA2001
  * Mod 01 06-25-2002 TEM Remove printer on/off. The parent process will do this.
  * End modification history
  *
  * Requires HP [[LaserJet]] (compatible) printer
  *
  * Specifications
  *
  * MESSAGE (passed)         - This is the actual data to be encoded.
  *
  * INDENT (passed)          - Spacing to indent message if it is printed below barcode.
  *
  * BAR.WIDTH (passed)       - If a whole number is passed it will be the number of
  *                            dots for a single bar (300 dpi).  If a number less
  *                            one is used it is assumed to be inches for a single
  *                            bar (ex .010 is the same as 3 dots).  If the value
  *                            is null or zero the default of 3 dots (.010") will be
  *                            used.  (max is 15 dots or .5")
  *
  * BAR.HEIGHT (passed)      - If a whole number is passed it will be the number of
  *                            dots for the overall barcode height (300 dpi). If a
  *                            decimal number is used, it is assumed to be inches.
  *                            (ex. for a 1/2 inch barcode use 150 or .5).  The
  *                            maximum is 900 dots or 3.0 inches.
  *
  * ORIENTATION (passed)     - Orientation of the barcode.  Use 'H' for horizontal
  *                            (lines going up and down) and 'V' for vertical. The
  *                            default is horizontal.
  *
  * PASSED.PARAMS (passed)   - Attr 1  = true   Print message text below barcode
  *                            Attr 2  = true   Subroutine will control printer
  *                            null             No message will print, caller will control printer
  *
  * PASSED.PARAMS (returned) - attr 10 = true   status code - 1   Null message
  *                                                           2   Message too long     (N[[/A]])
  *                                                           3   Invalid width param  (N[[/A]])
  *                                                           4   Invalid indent param (N[[/A]])
  *                                                           5   Invalid character    (N[[/A]])
  *                                                           0   OK
  *
  * Note: The barcode is printed from the current cursor position.  After
  *       the barcode is printed the cursor is repositioned back to its
  *       original coordinates.
  *
  * Calling program must set printer print position and close print job.
  *
  ****************************************
  *
  * Initialize
  *
  EQU BS     TO CHAR(8)
  EQU ESC    TO CHAR(27)
  *
  EQU FALSE  TO 0
  EQU TRUE   TO 1
  *
  EQU CODE.A TO 1                                                             ;* Code fields
  EQU CODE.B TO 2
  EQU CODE.C TO 3
  *
  USER.NO             = @USER.NO
  LOG.NAME            = @LOGNAME
  PHANTOM             = SYSTEM(25)
  *
  IF USER.NO >= 10000 THEN
     PHANTOM  = TRUE
  END
  *
  PROGRAM.NAME        = 'PRINT.BARCODE.128.HP.SUB'
  *
  ****************************************
  *
  * Main program
  *
  IF UNASSIGNED(PASSED.PARAMS) THEN
     PASSED.PARAMS  = ''
  END
  *
  PARAMS              = PASSED.PARAMS
  PRINT.MESSAGE.TEXT  = PARAMS<1>                                             ;* True if message text to be printed under barcode
  PRINTER.CONTROL     = PARAMS<2>                                             ;* True if this program is to turn printer on and off
  *
  * Validate parameters
  *
  * INDENT       - spaces to indent text message if printed
  * BAR.WIDTH    - width of each bar - number of dots at 300 dpi
  * BAR.HEIGHT   - barcode height - number of dots at 300 dpi
  * ORIENTATION  - H = horizontal, V = vertical
  *
  IF INDENT     = '' OR INDENT     = '0' OR NOT(NUM(INDENT))     THEN INDENT       = 0
  IF BAR.WIDTH  = '' OR BAR.WIDTH  = '0' OR NOT(NUM(BAR.WIDTH))  THEN BAR.WIDTH    = 3
  IF INDEX(BAR.WIDTH, '.', 1)                                    THEN BAR.WIDTH    = (BAR.WIDTH  * 300) 'R#0'
  IF BAR.WIDTH  > 15                                             THEN BAR.WIDTH    = 15
  *
  IF BAR.HEIGHT = '' OR BAR.HEIGHT = '0' OR NOT(NUM(BAR.HEIGHT)) THEN BAR.HEIGHT   = 150
  IF INDEX(BAR.HEIGHT, '.', 1)                                   THEN BAR.HEIGHT   = (BAR.HEIGHT * 300) 'R#0'
  IF BAR.HEIGHT > 900                                            THEN BAR.HEIGHT   = 900
  *
  IF NOT(ORIENTATION MATCHES 'H]V')                              THEN ORIENTATION  = 'H'
  *
  BEGIN CASE
  CASE MESSAGE = ''             ; STATUS.CODE  = 1                            ;* Null message
  CASE 1                        ; STATUS.CODE  = 0                            ;* OK - proceed
  END CASE
  *
  * If OK, set up and print
  *
  IF STATUS.CODE = 0 THEN
     GOSUB BUILD.BIT.TABLE
     *
     CHECK.SUM    = 0
     BAR.CNT      = 0
     X.COORD      = 0
     Y.COORD      = 0
     *
     * Print the start code
     *
     BEGIN CASE
     CASE MESSAGE[1,4] MATCHES '4N'
        CODE.FLD       = CODE.C
        BIT.TABLE.PTR  = 106
     CASE MESSAGE[1,1] < CHAR(32)                                             ;* Control character
        CODE.FLD       = CODE.A
        BIT.TABLE.PTR  = 104
     CASE TRUE
        CODE.FLD       = CODE.B
        BIT.TABLE.PTR  = 105
     END CASE
     *
   * PRINTER ON                                                               ;* Mod 01, Mod 02
     *
     IF PRINTER.CONTROL THEN                                                  ;* Mod 02
        PRINTER ON                                                            ;* Mod 02
     END                                                                      ;* Mod 02
     *
     GOSUB PRINT.BARCODE
     *
     * Print the bar code for each character
     *
     MESSAGE.LEN  = LEN(MESSAGE)
     *
     FOR CHR.PTR = 1 TO MESSAGE.LEN WHILE STATUS.CODE = 0
        BEGIN CASE
        CASE CODE.FLD # CODE.C AND MESSAGE[CHR.PTR,6] MATCHES '6N'
           BIT.TABLE.PTR  = 100                                               ;* From A or B to C
           *
           GOSUB PRINT.BARCODE
           *
           CODE.FLD       = CODE.C
        CASE CODE.FLD = CODE.C AND NOT(MESSAGE[CHR.PTR,2] MATCHES '2N')
           CHR            = MESSAGE[CHR.PTR,1]
           *
           LOCATE CHR IN BIT.TABLE<CODE.B> SETTING JUNK THEN
              BIT.TABLE.PTR  = 101                                            ;* From C to B
              *
              GOSUB PRINT.BARCODE
              *
              CODE.FLD       = CODE.B
           END ELSE
              BIT.TABLE.PTR  = 102                                            ;* From C to A
              *
              GOSUB PRINT.BARCODE
              *
              CODE.FLD       = CODE.A
           END
        END CASE
        *
        IF CODE.FLD = CODE.C THEN
           CHR      = MESSAGE[CHR.PTR,2]
           CHR.PTR += 1
        END ELSE
           CHR      = MESSAGE[CHR.PTR,1]
        END
        *
        LOCATE CHR IN BIT.TABLE<CODE.FLD> SETTING BIT.TABLE.PTR ELSE
           BEGIN CASE
           CASE CODE.FLD = CODE.A
              BIT.TABLE.PTR  = 101                                            ;* From A to B
              *
              GOSUB PRINT.BARCODE
              *
              CODE.FLD       = CODE.B
           CASE CODE.FLD = CODE.B
              BIT.TABLE.PTR  = 102                                            ;* From B to A
              *
              GOSUB PRINT.BARCODE
              *
              CODE.FLD       = CODE.A
           END CASE
           *
           LOCATE CHR IN BIT.TABLE<CODE.FLD> SETTING BIT.TABLE.PTR ELSE
              STATUS.CODE  = 5
           END
        END
        *
        IF STATUS.CODE = 0 THEN
           GOSUB PRINT.BARCODE
        END
     NEXT CHR.PTR
     *
     * Print the modulo 103 check character
     *
     IF STATUS.CODE = 0 THEN
        BIT.TABLE.PTR  = MOD(CHECK.SUM, 103) + 1
        *
        GOSUB PRINT.BARCODE
        *
        * Print the stop character
        *
        BIT.TABLE.PTR  = 107
        *
        GOSUB PRINT.BARCODE
     END
     *
     * Print message text below barcode if required
     *
     IF PRINT.MESSAGE.TEXT THEN
        *
        * Advance print position
        *
        PRINT
        PRINT
        PRINT
        *
        IF BAR.WIDTH > 150 THEN                                               ;* Width of each bar - number of dots at 300 dpi
           PRINT
        END
        *
        PRINT STR(' ', INDENT + INT(BAR.WIDTH / 4) + 10): MESSAGE
     END
     *
     * Reposition the cursor
     *
     PRINT ESC: '*p-': X.COORD: 'x-': Y.COORD: 'Y':
     *
   * PRINTER OFF                                                              ;* Mod 01, Mod 02
     *
     IF PRINTER.CONTROL THEN                                                  ;* Mod 02
        PRINTER OFF                                                           ;* Mod 02
     END                                                                      ;* Mod 02
  END
  *
  PASSED.PARAMS<10>   = STATUS.CODE
  *
  RETURN
  *
  ****************************************
  *
  * Subroutines
  *
****************
BUILD.BIT.TABLE: * Build bit table for characters
****************
  *
  BIT.TABLE           = ''
  MV.PTR              = 0
  *
  FOR ASCII.VALUE = 32 TO 95
     MV.PTR              += 1
     BIT.TABLE<1,MV.PTR>  = CHAR(ASCII.VALUE)
  NEXT ASCII.VALUE
  *
  FOR ASCII.VALUE = 0 TO 31
     MV.PTR              += 1
     BIT.TABLE<1,MV.PTR>  = CHAR(ASCII.VALUE)
  NEXT ASCII.VALUE
  *
  FOR ASCII.VALUE = 32 TO 127
     BIT.TABLE<2, ASCII.VALUE - 31>  = CHAR(ASCII.VALUE)
  NEXT ASCII.VALUE
  *
  FOR ASCII.VALUE = 0 TO 99
     BIT.TABLE<3, ASCII.VALUE + 1>  = ASCII.VALUE 'R%2'
  NEXT ASCII.VALUE
  *
  BIT.TABLE<4>        = '212222]222122]222221]121223]121322]131222]122213]122312'
  BIT.TABLE<4,-1>     = '132212]221213]221312]231212]112232]122132]122231'
  BIT.TABLE<4,-1>     = '113222]123122]123221]223211]221132]221231]213212'
  BIT.TABLE<4,-1>     = '223112]312131]311222]321122]321221]312212]322112'
  BIT.TABLE<4,-1>     = '322211]212123]212321]232121]111323]131123]131321'
  BIT.TABLE<4,-1>     = '112313]132113]132311]211313]231113]231311]112133'
  BIT.TABLE<4,-1>     = '112331]132131]113123]113321]133121]313121]211331'
  BIT.TABLE<4,-1>     = '231131]213113]213311]213131]311123]311321]331121'
  BIT.TABLE<4,-1>     = '312113]312311]332111]314111]221411]431111]111224'
  BIT.TABLE<4,-1>     = '111422]121124]121421]141122]141221]112214]112412'
  BIT.TABLE<4,-1>     = '122114]122411]142112]142211]241211]221114]413111'
  BIT.TABLE<4,-1>     = '241112]134111]111242]121142]121241]114212]124112'
  BIT.TABLE<4,-1>     = '124211]411212]421112]421211]212141]214121]412121'
  BIT.TABLE<4,-1>     = '111143]111341]131141]114113]114311]411113]411311'
  BIT.TABLE<4,-1>     = '113141]114131]311141]411131]211412]211214]211232'
  BIT.TABLE<4,-1>     = '2331112'
  *
  RETURN
  *
**************
PRINT.BARCODE: * Print one character of barcode
**************
  *
  BAR.PATTERN         = BIT.TABLE<4,BIT.TABLE.PTR>
  BAR.LEN             = LEN(BAR.PATTERN)
  *
  FOR BAR.PTR = 1 TO BAR.LEN STEP 2
     BAR  = BAR.PATTERN[BAR.PTR,     1]
     SPC  = BAR.PATTERN[BAR.PTR + 1, 1]
     *
     IF ORIENTATION = 'H' THEN                                                ;* Horizontal
        PRINT ESC: '*c': BAR * BAR.WIDTH: 'a': BAR.HEIGHT: 'b0P':
        *
        X.COORD.ADJUST  = (BAR * BAR.WIDTH) + (SPC * BAR.WIDTH) - 1
        *
        PRINT ESC: '*p+': X.COORD.ADJUST: 'x+0Y':
        *
        X.COORD        += X.COORD.ADJUST
     END ELSE                                                                 ;* Vertical
        PRINT ESC: '*c': BAR.HEIGHT: 'a': BAR * BAR.WIDTH: 'b0P':
        *
        Y.COORD.ADJUST  = (BAR * BAR.WIDTH) + (SPC * BAR.WIDTH) - 1
        *
        PRINT ESC: '*p+0x+': Y.COORD.ADJUST: 'Y':
        *
        Y.COORD        += Y.COORD.ADJUST
     END
  NEXT BAR.PTR
  *
  IF BAR.CNT = 0 THEN
     CHECK.SUM += (BIT.TABLE.PTR - 1)
  END ELSE
     CHECK.SUM += (BIT.TABLE.PTR - 1) * BAR.CNT
  END
  *
  BAR.CNT            += 1
  *
  RETURN
  *
  ****************************************
  *
  * End of program
  *
  END