BarCode128
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