; ; ZDB23.C - Postal DPBC Barcode Module ; .comment ~ ; Start of comment area DPBC Barcodes The following barcode definitions comform to the U.S. Postal Service publication 'Letter Mail Barcode Update' dated May 1992. Copies of this publication may be obtained through your post office business center or by calling the USPS Coding Accuracy Support Systems at 1-800-238-3150. ZDB prints the full 12-digit, 62-bar DPBC, which is now required by the Postal Service for bulk mailing discounts and whenever barcodes are printed by the mailer. The DPBC adds the last two digits of the street address or P.O. Box plus a correction character to the 9 digit ZIP+4 ZIP code when printing a barcode. The sample address: 21460 Bear Creek Road Los Gatos CA 95030-9429 has a DPBC of 950309429603, where the last digit, the correction character 3, is added to the sum of the bar code digits to make the sum a multiple of 10. While ZDB compiles the extra DPBC digits during the barcode printing process, they are not included as part of the printed address. DPBC barcodes wil be printed only if the ZIP Code field contains a full ZIP+4 9-digit zip code and the Country field is empty. DPBC barcodes can't be printed from five-digit zip code entries. Is it time to make a WSF file listing from your database and take it to the Post Office for a look through the ZIP Code book?? Barcode characters contain 2 full bars per 5-bar character in a weighted binary code. Weights: 74210 ===== zero: 11... Weight=7+4=11 (Defined as = 0) one: ...11 Weight=1+0=1 two: ..1.1 Weight=2+0=2 three: ..11. Weight=2+1=3 four: .1..1 Weight=4+0=4 five: .1.1. Weight=4+1=5 six: .11.. Weight=4+2=6 seven: 1...1 Weight=7+0=7 eight: 1..1. Weight=7+1=8 nine: 1.1.. Weight=7+2=9 The barcode starts and ends with a full 'frame' bar. The sample barcode above would be printed above the main address as: ||.|...|.|.||.....||.||...|.|...|..|..|.||.|...||..||.....||.| \-9-/\-5-/\-0-/\-3-/\-0-/\-9-/\-4-/\-2-/\-9-/\-6-/\-0-/\-3-/ The sample digit markers, above, are for illustration purposes only and aren't printed as part of the barcode. The full sample 'label' would look something like this: ||.|...|.|.||.....||.||...|.|...|..|..|.||.|...||..||.....||.| Terry Hazen 21460 Bear Creek Road Los Gatos CA 95030-9429 Barcode Printing ZDB prints the barcodes in bitmapped graphics. The required barcode character dimensions are: Full bar height = 0.115" - 0.135" (0.125" +/- 0.010") about 1/8" Half bar height = 0.040" - 0.060" (0.050" +/- 0.010") about 3/64" Bar widths = 0.015" - 0.025" (0.020" +/- 0.005") about 1/64" Bar pitch = 22 +/- 2 bars/inch = 0.0416" - 0.0500" spacing. Standard 120dpi printing = 20 bars/inch. Most 9-pin printers will probably require 2 passes to print conforming barcodes containing 1/8" full bars. ZDB is distributed configured for 2-pass barcode printing. Many 24-pin printers, however, can print 1/8" full bars in one pass. Try printing some sample labels containing barcodes and measure the full and half bar heights to see if their heights conform to the requirements to see whether the distribution default is adequate or if you need to reconfigure ZDB. ZDB may be reconfigured to turn off the second barcode printing pass. For help configuring ZDB, see the help screens in ZDB19.CFG or the configuration overlay code in ZDB19OVL.Z80. For more information on the barcodes, see the beginning of ZDB19.C, the barcode module. DPBC Placement The ends of the barcode must be at least 1/8" from label edges and at least 1/2" from the envelope edges. The barcode may be located as high as 4" from the bottom of the envelope, but the lower 5/8" of the envelope must remain empty (a 'barcode clear zone'.) ~ ; End of comment area ;----------------------------------------------------------------------- ; ; Bitmapped barcode character definitions (high 5 bits only:) ; ; Weights: 74210--- ; ========= zero: db 11000000b ; Weight=7+4=11(=0 by definition) one: db 00011000b ; Weight=1+0=1 two: db 00101000b ; Weight=2+0=2 three: db 00110000b ; Weight=2+1=3 four: db 01001000b ; Weight=4+0=4 five: db 01010000b ; Weight=4+1=5 six: db 01100000b ; Weight=4+2=6 seven: db 10001000b ; Weight=7+0=7 eight: db 10010000b ; Weight=7+1=8 nine: db 10100000b ; Weight=7+2=9 ;----------------------------------------------------------------------- ; barcode:ld hl,ain ; Initialize printer for barcode call clpstr ; and address call lmargin ; Space over to left margin ; ; Parse address, country, zip fields to see if we need a line feed ; between the return address and address, assuming a maximum of 5 ; lines, including a possible leading linefeed and a possible barcode, ; can be used included the address. Print initial line feed if ; we have free lines. ; chklf: ld a,(lra) ; Return address? or a jr z,chkbc ; No, skip initial line feed ; ld b,2 ; Initialize max number of lines ld a,(addr1) ; Check first address line or a jr z,chklf0 ; dec b ; Decrement free lines ; chklf0: ld a,(addr2) ; Check second address line or a jr z,chklf1 ; dec b ; Decrement free lines jr z,chkbc ; chklf1: ld a,(ctry) ; Check country or a jr z,chklf2 ; inc b ; Increment free lines ; chklf2: ld a,b ; Test for free lines or a call nz,nline ; Print initial line feed if so ; ; See if we should print a barcode, return NZ if so ; chkbc: ld a,(ctry) ; Check country or a ret nz ; Not empty, skip barcode ; ld a,(zip+5) ; Check possible ZIP dash cp '-' ld a,(zip+9) ; Check last ZIP digit (with dash) jr z,tstzip ; Dash, check last zip digit ; ld a,(zip+8) ; No dask, check last zip digit ; tstzip: or a jp z,nline ; Add linefeed and quit ; ; Initialize barcode buffer and checksum byte ; prtbc: ld hl,barcod ; Point to barcode buffer push hl ; Save buffer pointer ld (hl),0 ; Fill first byte ld de,barcod+1 ; Point to second byte ld bc,buflen ; Buffer length ldir ; ; Fill barcode character buffer ; pop de ; Point to buffer call movbar ; Start with bar ; ld hl,zip ; Point to zip field ld b,10 ; Length of zip code field ; ziplp: push hl ; Save zip pointer call movchr ; Move barcode character to buffer pop hl ; Restore zip pointer inc hl ; Point to next character djnz ziplp ; Do all 9 digits ; ; Parse address fields for DP digits, as defined by the US Postal ; Service. ; dpbc1: ld hl,addr1 ; Start with first address field call finddp ; Parse for DP digits jr nz,movdp ; Found ; ld hl,addr2 ; Try second address field call finddp ; Parse for DP digits jr nz,movdp ; Found ; ld hl,'99' ; Use DPBC anomaly characters ; movdp: ld a,l ; Get first character call isdigit ; Make sure it's a digit jr z,movdp0 ; Yes ; ld a,'0' ; Replace leading character with '0' ; movdp0: push hl ; Save pair call movchr0 ; Make BCD, move character pop hl ; Restore pair ld a,h ; Get second character call movchr0 ; Make BCD, move character ; ; Calculate checksum ; ccsum: ld a,(chksum) ; Get sum of digits ld b,a ; In B xor a sub b ; Checksum + Sum = 0 (last digit) daa and 0fh ; Low bcd digit call zipars ; Move checksum character call movbar ; End with bar ; ; Print barcode pass 1 ; ld a,(strikes) ; Get number of strikes/pass ld b,a ld e,on ; Set mask for pass 1 call printbc ; Print barcode ; ld hl,setlf ; Set short line spacing ld a,(hl) ; Check length or a jp z,nline ; Skip second pass ; ; Print barcode pass 2 ; call clpstr call nline ; Set new line and left margin ; ld a,(strikes) ; Get number of strikes/pass ld b,a ld a,(hbar) ; Get mask for pass 2 ld e,a ; Set mask call printbc ; Print barcode ; ld hl,deflf ; Restore default line spacing call clpstr ; jp nline ; Quit to set new line and left margin ;----------------------------------------------------------------------- ; ; Barcode subroutines ; ; Parse 0-terminated string for DP digits ; Entry:HL points to string ; Exit: NZ, A=first DP digit, L=first DP digit, H=second DP digit ; Z = digits not found ; Uses: AF, HL ; finddp: ld a,(hl) ; Get first character or a ret z ; Field is empty call isdigit ; Starts with digit? jr z,getnd ; Yes, search for first non-digit ; ; Search for PO box string ; getx: inc hl ld a,(hl) ; Get character or a ret z ; End of field ; cp 'x' ; Box? jr z,fndx ; Yes cp 'X' ; Box? jr nz,getx ; No, keep trying ; fndx: inc hl ; Check next ld a,(hl) ; Get character dec hl or a ; End of field? ret z ; Yes ; cp ' ' ; Should be space jr nz,getx ; No, keep trying ; inc hl ; Skip space ; ; Locate first non-digit ; getnd: inc hl ; Point to next ld a,(hl) ; Get character or a jr z,dpfnd ; End of field ; cp ' ' jr z,dpfnd ; End of digit string ; call isdigit ; Digit? jr z,getnd ; Yes, keep trying ; ; We have a non-digit, check next one ; inc hl ; Check for imbedded non-digit ld a,(hl) dec hl or a ; End of field? jr z,dpfnd ; Yes ; cp ' ' ; End of digit string? jr z,dpfnd ; Yes ; getdig: call isdigit jr z,getnd ; We have a digit again, look for end ; inc hl ld a,(hl) or a jr nz,getdig ; Non-digit, look for next digit ; ; Conforming termination found ; dpfnd: dec hl ; Back up to last digit ld a,(hl) cp 'x' ; Make sure we don't back up too far ret z cp 'X' ret z ; call isdigit jr nz,dpfnd ; dec hl ; Back up to check for slash dec hl ld a,(hl) cp '/' ; Quit if slash ret z ; inc hl ; Check first digit ld a,(hl) cp '/' ; Quit if slash ret z ; call lhlhl ; Get digits in HL or 0ffh ; Set good find flag ret ; ; Move barcode character to buffer, update checksum ; movchr: ld a,(hl) ; Get zip digit call isdigit ; Digit? ret nz ; No, skip it ; movchr0:sub 30h ; Make BCD jr z,zipars ; '0', move zero character, skip update ; ld c,a ; Save BCD digit ld a,(chksum) ; Get sum of digits add a,c ; Update it daa ld (chksum),a ; Save sum of digits ld a,c ; Restore zip digit ; ; Parse zip digit to get pointer to barcode character ; zipars: ld hl,zero ; Point to barcode string table add a,l ; Add offset to start of table ld l,a jr nc,bcdisp ; inc h ; ; Move barcode character to buffer ; bcdisp: push bc ; Save counter ld a,(hl) ; Get barcode character ld b,5 ; 5 strokes per character ; bclp: rla ; Shift hi bit into carry ld c,a ; Save code byte call c,movbar ; Bit set, move full bar call nc,movhbar ; Bit not set, move half bar ld a,c ; Restore code byte djnz bclp pop bc ; Restore counter ret ; ; Move half bar character to buffer ; movhbar:ld a,(hbar) ; Half bar character jr movbc ; ; Move bar character to buffer ; movbar: ld a,(fbar) ; Full bar character ; ; Move barcode character in A to barcode buffer (pointer in DE) ; movbc: push af ; Save flags push bc ; And counter ld (de),a ; Move 2 copies of the character inc de ld (de),a inc de ; ; Zero-fill space between bars ; ld b,4 ; 4 zero's will do it ; zlp: xor a ld (de),a inc de djnz zlp ; pop bc ; Restore counter pop af ; And flags ret ; ; Set up graphics and buffer pointers ; setg: ld hl,setgraf ; Set graphics call clpstr ld hl,barcod ; Point to barcode buffer ld bc,buflen ; Set length of buffer ret ; ; Print barcode b times with byte mask in e ; printbc:push bc ; Save strike count call setg ; Set up graphics and pointers ; pcstr1: ld a,(hl) ; Get character inc hl ; Point to next character and e ; Mask call lout ; Print character dec bc ld a,b or c jr nz,pcstr1 ; pop bc ; Restore strike count djnz pcstr2 ret ; pcstr2: ld a,cr ; Reset print head call lout push bc ; Save strike count call lmargin ; Reset left margin pop bc ; Restore strike count jr printbc ; Do specified number of strikes ; ; End of ZDB.C ;