FLOSS Manuals

 English |  Español |  Français |  Italiano |  Português |  Русский |  Shqip

Python Scripting with Scribus

postnet.py

This was something I made strictly for my own use. Scribus of course has the Barcode Generator plugin, which works Ok, though personally I find the interface a little clunky. It does what it does and you cannot change features, like bar length or the font for the text/numbers if included. It generates a PostScript item that you place on the page. It's also not scriptable.

The first task for creating Postnet codes for the US Postal Service is research into the requirements, so that you make bars of adequate length and they are spaced properly. There are two lengths of bars, with patterns of these bars corresponding to various digits. In addition, at the end of the bars there is a "correction code", which is an added pattern of bars so that the sum of all the digits is divisible by 10.

#!/usr/bin/env python

# File: postnet.py
# this version 2006.03.07
# adds the correction code:
# the sum of all the digits
# must be divisible by 10

import scribus

postcode = ['llsss','sssll','sslsl','sslls','slssl','slsls','sllss','lsssl','lssls','lslss']
a = 1.44      #line width
b="Black"     #line color
relx=47      #Start X
rely=323      #Start Y
correctnum = 0
if scribus.haveDoc():
    S = scribus.valueDialog('Postnet Barcode','Enter your Zip or Zip+4')
    scribus.setRedraw(1)
    scribus.setUnit(0)
    d = scribus.createLine(relx,rely,relx+9,rely,) #Beginning long framing line
    scribus.setLineWidth(a, d)
    scribus.setLineColor(b, d)
    rely = rely + 3.4
    for x in S[0:]:
        if x.isdigit():
            xnum = int(x)
            correctnum += xnum      # Building the sum of all the digits
            code = postcode[xnum]
            for y in code[0:]:
                if y == 'l':
                    d = scribus.createLine(relx,rely,relx+9,rely,) #Long line
                    scribus.setLineWidth(a, d)
                    scribus.setLineColor(b, d)
                    rely = rely + 3.4
                elif y == 's':
                    d = scribus.createLine(relx,rely,relx+3.6,rely,) #short line
                    scribus.setLineWidth(a, d)
                    scribus.setLineColor(b, d)
                    rely = rely + 3.4
    correctstr = str(correctnum)  # Here is where the correction code is added
    correctdig = int(correctstr[-1])
    if correctdig != 0:
        correctdig = 10 - correctdig
    code = postcode[correctdig]
    for y in code[0:]:
        if y == 'l':
            d = scribus.createLine(relx,rely,relx+9,rely,) #Long line
            scribus.setLineWidth(a, d)
            scribus.setLineColor(b, d)
            rely = rely + 3.4
        elif y == 's':
            d = scribus.createLine(relx,rely,relx+3.6,rely,) #short line
            scribus.setLineWidth(a, d)
            scribus.setLineColor(b, d)
            rely = rely + 3.4
            
    d = scribus.createLine(relx,rely,relx+9,rely,) #Ending long framing line
    scribus.setLineWidth(a, d)
    scribus.setLineColor(b, d)
    scribus.redrawAll()

At the beginning of the script you see I create a list, postnet[]. What this contains are the rules for the various digits. As you can see, there are 5 bars for each digit. postnet[0] or 'llsss' is for the digit 0, which means that there are 2 long lines followed by 3 short lines. We then set some variables for the width of the lines we'll make, the color, and the starting point for these lines, which is at XPos, YPos of 43, 323. correctnum is going to be our correction digit, which we initialize at 0.

As you can see, even though we use an if statement to check if there is a document, I don't have a corresponding else clause, so if there is no document, the script just quits, without any feedback. In the US, the basic postal code is a 5-digit Zip code, which directs the mail to a particular Post Office branch. There is also the option of Zip+4, where 4 more digits are added which correspond to a particular address. This script will automatically handle both types. Zip+4 is usually written as a sequence of 5 digits, a hyphen, then the last 4 digits, even though the Postnet code contains only the digits.

Postnet bar codes also begin and end with what's called a framing line, basically a single long line. Here we see the sequence for creating lines with Scripter:

    d = scribus.createLine(relx,rely,relx+9,rely,) #Beginning long framing line
    scribus.setLineWidth(a, d)
    scribus.setLineColor(b, d)

We first create the line's dimensions with a starting XPos, YPos, then the ending XPos, YPos as you see, the line is horizontal and has a length of 9 points. Once the line is created, then we can assign a width, and a line color.

After the framing line, we then proceed to pick apart postnet[] digit by digit, marching 3.4 points down the page after each line. In case you wonder why I'm creating horizontal lines in a vertical sequence, this is because of how I have used this script. I also have a template for No. 10 envelopes, which is placed and oriented so that I can print them with my printer, where I feed the left edge of the envelope first into the printer. This location and arrangement of the Postnet code corresponds to the place under the mailing address for this template.

So what about this correction code? If we think about it, what we're saying for the sum of all digits to be divisible by 10, the sum should end with a zero. To that end, we convert the correctnum to a string and check the last character, correctstr[-1]. Our correction digit is then either 0 or 10-int(correctstr[-1]). After adding the code for that and the final framing line, we're done.

code39.py

This was also a personal project, but part of something bigger. Being the zealous Scribus user that I still am, I wanted to recreate my own version of the pages of the patients' hospital charts. This was back in the time when our hospital still had paper charts for notes, even though an increasing amount of information was on the computer system. If I could create my own chart pages, customized to the particular patient, I could then use Scribus to make my notes as I made my hospital rounds each day. As a consequence, I had the most legible notes of any doctors making rounds, and needless to say, people were impressed. This also meant that I could make an additional copy of the page to take back to the office for the patient's office chart (when this was useful). Some doctors even came up with their own schemes for making their notes this way. With Scribus, I still had them beat by a mile, because I could also incorporate into my notes selected images from a patient's CT or MRI scans, and thus explain what I felt was important in the studies, and I received many thanks from the doctor and nursing staff for the teaching that come from this.

Breaking down this idea into what I needed to know, the overall layout of the page was simple, with a series of lines. Even though I was mostly using Scribus for the notes, sometimes I might add something hand-written, and other doctors could also add to the page to fill it. In the upper right corner of page was patient identification information, including their hospital number in legible form and also as a barcode. But what barcode? This turned out to be an easy question to answer, since I just went to Scribus and Barcode Generator, plugging in hospital numbers, and quickly found out that this was a Code 39 barcode.

This then led to research into what Code 39 is, easily found on the internet, with precise descriptions. Code 39 is a sequence of thin and thick lines, separated by thin and thick spaces. Unlike Postnet, Code 39 can handle all the letters of the alphabet, all digits, and even some symbols.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# File: code39.py
# Now will encode all defined characters, plus the start/stop character
# Any other character causes the script to exit

import scribus
import sys

# first the codes for numbers 0-9
code39 = ['nnswwn','wnsnnw','nwsnnw','wwsnnn','nnswnw','wnswnn','nwswnn','nnsnww','wnsnwn','nwsnwn']
# next add the codes for A-Z and the rest
code39.extend(['wnnsnw','nwnsnw','wwnsnn','nnwsnw','wnwsnn','nwwsnn','nnnsww','wnnswn','nwnswn'])
code39.extend(['nnwswn','wnnnsw','nwnnsw','wwnnsn','nnwnsw','wnwnsn','nwwnsn','nnnwsw','wnnwsn'])
code39.extend(['nwnwsn','nnwwsn','wsnnnw','nswnnw','wswnnn','nsnwnw','wsnwnn','nswwnn'])
code39.extend(['nswnwn','nsnsnsnn','nnsnsnsn','nsnnww','wsnnwn','nsnsnnsn','nsnnsnsn'])

startstop = 'nsnwwn'
narrow = 1.0   # narrow line width
wide = 2.2    # wide line width
b="Black"     #line color

if scribus.haveDoc():
    S = scribus.valueDialog('Code 39','Enter Numbers or Uppercase Letters')
    height = scribus.valueDialog('Code 39','Enter Height of Bars (Points)')
    height = int(height)
    location = scribus.valueDialog('Code 39','Enter New X-Pos Y-Pos\n(No Comma, just space between)', '200  100')
    relpos = location.split()
    relx = int(relpos[0])
    rely = int(relpos[1])
    origx = relx
    humanread = scribus.valueDialog('Code 39','Print Human-Readable Code Too?\n(Any change means no)', 'Yes')
    scribus.setRedraw(1)
    scribus.setUnit(0)

    code = startstop

    for x in S[0:]:
        if x.isdigit():
            xnum = int(x)
            code = code + code39[xnum]
        elif ((ord(x) > 64) and (ord(x) < 91)):   # ord(character) yields the ascii value
        xnum = ord(x) - 55
        code = code + code39[xnum]
        elif (ord(x) == 32):                      #  space
            code = code + code39[36]
        elif ((ord(x) == 36) or (ord(x) == 37)):  #  $ and %
            xnum = ord(x) + 1
            code = code + code39[xnum]
        elif ((ord(x) > 44) and (ord(x) < 48)):   #  - . /
            xnum = ord(x) - 6
            code = code + code39[xnum]
        elif (ord(x) == 43):                      #  +
            code = code + code39[42]
        elif (ord(x) == 42):
            code = code + startstop               #  * (adding for completeness)
        else:
            scribus.messageBox('OOPS!',S + '\nCode 39 does not encode this character: '+x,scribus.ICON_NONE,button1=scribus.BUTTON_OK)
            sys.exit(1)

    code = code + startstop

    for y in code[0:]:
        if y == 'n':
            relx = relx + narrow/2
            d = scribus.createLine(relx,rely,relx,rely + height,) #narrow line
            scribus.setLineWidth(narrow, d)
            scribus.setLineColor(b, d)
            scribus.setFillColor(b, d)
            relx = relx + narrow + narrow/2
        elif y == 'w':
            relx = relx + wide/2
            d = scribus.createLine(relx,rely,relx,rely + height,) #wide line
            scribus.setLineWidth(wide, d)
            scribus.setLineColor(b, d)
            scribus.setFillColor(b, d)
            relx = relx + narrow + wide/2
        elif y == 's':                                      #for wide space
            relx = relx + wide

    if (humanread == 'Yes'):
        t = scribus.createText(origx, rely+height+3, relx - origx, 15)
        scribus.setText(S, t)
        scribus.setFont("DejaVu Sans Book", t)
        scribus.setFontSize(8, t)
        scribus.setTextAlignment(scribus.ALIGN_CENTERED, t)

    scribus.redrawAll()

else:
    scribus.messageBox('OOPS!','You must have a document open to run this script',scribus.ICON_WARNING,button1=scribus.BUTTON_OK)
    sys.exit(1)

At the beginning, you can see the greater complexity of the bar and space sequences, where n and w represent narrow and wide lines. The s denotes a wider space than the default space I create between all bars, the narrow space.

User input starts with entering the sequence of numbers, letters, and symbols to be encoded. We then parse the entered sequence, creating one continuous string of n's, w's, and s's. In case we find a character which is not part of code 39, we bail out with the message at the bottom. Now we have this large string, which character by character creates the sequence of bars and spaces. We also have an option at the end to add human-readable characters to our barcode. Notice how we exactly size this text frame to the length of the code, then center the character glyphs.

As I suggested above, this Python code was then incorporated into the larger script which created the documentation page, complete with patient information and this barcode. Once I created this, I could then save the document on a hospital computer, so I wouldn't have to re-create the basic form again. When the patient was discharged, I deleted the file.

There has been error in communication with Booktype server. Not sure right now where is the problem.

You should refresh this page.