Generating a Code39 Barcode: Difference between revisions
(37 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
{{Scripting Index}} | |||
Here are the Scribus operations you will find examples for in this script: | |||
{| | |||
| valign=top| | |||
* Testing for and using an existing document | |||
* Creating a number of lines using a standardized scheme (Code 39 specifications) | |||
* Using valueDialog for user input, also for more than one value per dialog, using the Python '''split''' function | |||
| | |||
* Some limited testing for valid user input – encodable characters | |||
* Creating a text frame at a specified relative page location and with a size defined by the barcode width | |||
* Setting fonts, and font characteristics, such as its size and alignment of text in the frame | |||
* Using messageBox for user feedback | |||
|} | |||
====How this script came to be==== | |||
The reason for writing this script was that I had already written a script for modifying a form we use, and on this form are barcodes, one of which indicates the type of form, but the other is variable according to the content of the page. | The reason for writing this script was that I had already written a script for modifying a form we use, and on this form are barcodes, one of which indicates the type of form, but the other is variable according to the content of the page. | ||
The script creates that custom part, which has a 10-digit number, then underneath is the barcode. By trial and error I determined that this was a Code39 barcode. Unfortunately, the barcode generator in Scribus cannot be scripted, and in fact you cannot make a custom size for the barcode, so I was copying the 10-digit number, then running Barcode generator, then resizing the created code, which is a PostScript creation, so when it's resized, the width of the bars may change. So far it's been Ok, but this might affect the scanning process. | The script creates that custom part, which has a 10-digit number, then underneath is the barcode. By trial and error I determined that this was a Code39 barcode. Unfortunately, the barcode generator in Scribus cannot be scripted, and in fact you cannot make a custom size for the barcode, so I was copying the 10-digit number, then running Barcode generator, then resizing the created code, which is a PostScript creation, so when it's resized, the width of the bars may change. So far it's been Ok, but this might affect the scanning process. | ||
So here is a first attempt, '''code39.py'''. I had thought it was rather slow, but rechecking shows acceptable speed on various computers. | So here is a first attempt, '''code39.py'''. I had thought it was rather slow, but rechecking shows acceptable speed on various computers. The first iterations would only generate a code for digits and uppercase letters (plus the start/stop character), but now it's complete. | ||
====Oh, Why Not?==== | ====Oh, Why Not?==== | ||
Line 14: | Line 28: | ||
|I've also added a warning when you try to code a character that this script won't, so you get a message like this: | |I've also added a warning when you try to code a character that this script won't, so you get a message like this: | ||
As written, it stops at the first non-codable character, even though it does show you your entire entry. In this example '^' would also not be encodable. | |||
|[[Image:Code39_error.png]] | |[[Image:Code39_error.png]] | ||
|} | |||
====Maybe I've Got It Done Now==== | |||
{| width=80% | | |||
|The final itch to scratch were those remaining characters, so now the Code 39 set is complete. | |||
The python is a bit clumsy, but it works. | |||
|[[Image:Code39_results2.png]] | |||
|} | |||
====Somebody Please STOP Me!==== | |||
{| width=80% | | |||
|valign=top|Ok, now let's make it more flexible. Instead of hard-coded X-Pos and Y-Pos, we'll add the ability to assign these. By using the Python string '''split''' function, we can enter both values with one dialog, and for those times when you just want to get it on the page and then move it later, we'll put in some default values. Note the '''split''' syntax, and also that it discards however much whitespace there is between your values. These will be strings, so we need to convert to integer. | |||
I also have added a bailout if you run the script with no document open, since otherwise Scribus will just hang when ''if scribus.haveDoc()'' fails. | |||
| [[Image:Code39_location.png]] | |||
|} | |} | ||
====code39.py==== | ====code39.py==== | ||
< | <syntaxhighlight lang=python> | ||
#!/usr/bin/env python | #!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||
# **************************************************************************** | |||
# 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. | |||
# | |||
# **************************************************************************** | |||
# File: code39.py | # File: code39.py | ||
# Based on postnet2.py originally 2006.03.06 Gregory Pittman | # Based on postnet2.py originally 2006.03.06 Gregory Pittman | ||
# this version 2010.08. | # this version 2010.08.05 © Gregory Pittman, 2010 | ||
# encodes numbers and letters, plus | # encodes numbers and letters, plus all other Code 39 characters | ||
""" | """ | ||
Simple operation. | Simple operation. | ||
First dialog asks for your code (numbers and uppercase letters), | First dialog asks for your code (numbers and uppercase letters, plus space, period, | ||
as many characters as you want. | -,*,$,/,+,%) i.e., all characters allowed by Code 39, as many characters as you want. | ||
Second dialog asks for height of bars in points. | Second dialog asks for height of bars in points. | ||
Third dialog asks for the X-Pos and Y-Pos, separated only be whitespace, no comma! | |||
Fourth dialog confirms that you want to print the characters underneath. | |||
The start/stop character (*) is automatically added and does not show in the | |||
human-readable sequence. | |||
""" | """ | ||
Line 47: | Line 97: | ||
code39.extend(['nnwswn','wnnnsw','nwnnsw','wwnnsn','nnwnsw','wnwnsn','nwwnsn','nnnwsw','wnnwsn']) | code39.extend(['nnwswn','wnnnsw','nwnnsw','wwnnsn','nnwnsw','wnwnsn','nwwnsn','nnnwsw','wnnwsn']) | ||
code39.extend(['nwnwsn','nnwwsn','wsnnnw','nswnnw','wswnnn','nsnwnw','wsnwnn','nswwnn']) | code39.extend(['nwnwsn','nnwwsn','wsnnnw','nswnnw','wswnnn','nsnwnw','wsnwnn','nswwnn']) | ||
# and these are for the rest | |||
code39.extend(['nswnwn','nsnsnsnn','nnsnsnsn','nsnnww','wsnnwn','nsnsnnsn','nsnnsnsn']) | |||
startstop = 'nsnwwn' | startstop = 'nsnwwn' | ||
Line 52: | Line 104: | ||
wide = 2.2 # wide line width | wide = 2.2 # wide line width | ||
b="Black" #line color | b="Black" #line color | ||
if scribus.haveDoc(): | if scribus.haveDoc(): | ||
Line 60: | Line 109: | ||
height = scribus.valueDialog('Code 39','Enter Height of Bars (Points)') | height = scribus.valueDialog('Code 39','Enter Height of Bars (Points)') | ||
height = int(height) | 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') | humanread = scribus.valueDialog('Code 39','Print Human-Readable Code Too?\n(Any change means no)', 'Yes') | ||
scribus.setRedraw(1) | scribus.setRedraw(1) | ||
Line 73: | Line 127: | ||
xnum = ord(x) - 55 | xnum = ord(x) - 55 | ||
code = code + code39[xnum] | 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: | else: | ||
scribus.messageBox('OOPS!',' | scribus.messageBox('OOPS!',S + '\nCode 39 does not encode this character: ' + x,scribus.ICON_WARNING,button1=scribus.BUTTON_OK) | ||
sys.exit(1) | sys.exit(1) | ||
Line 104: | Line 170: | ||
scribus.redrawAll() | scribus.redrawAll() | ||
scribus.docChanged(1) | |||
else: | |||
scribus.messageBox('OOPS!','You must have a document open to run this script',scribus.ICON_WARNING,button1=scribus.BUTTON_OK) | |||
sys.exit(1) | |||
</ | </syntaxhighlight> | ||
====Line Positions==== | ====Line Positions==== |
Latest revision as of 23:46, 11 February 2018
Here are the Scribus operations you will find examples for in this script:
|
|
How this script came to be
The reason for writing this script was that I had already written a script for modifying a form we use, and on this form are barcodes, one of which indicates the type of form, but the other is variable according to the content of the page.
The script creates that custom part, which has a 10-digit number, then underneath is the barcode. By trial and error I determined that this was a Code39 barcode. Unfortunately, the barcode generator in Scribus cannot be scripted, and in fact you cannot make a custom size for the barcode, so I was copying the 10-digit number, then running Barcode generator, then resizing the created code, which is a PostScript creation, so when it's resized, the width of the bars may change. So far it's been Ok, but this might affect the scanning process.
So here is a first attempt, code39.py. I had thought it was rather slow, but rechecking shows acceptable speed on various computers. The first iterations would only generate a code for digits and uppercase letters (plus the start/stop character), but now it's complete.
Oh, Why Not?
Maybe I've Got It Done Now
The final itch to scratch were those remaining characters, so now the Code 39 set is complete.
The python is a bit clumsy, but it works. |
Somebody Please STOP Me!
code39.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ****************************************************************************
# 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.
#
# ****************************************************************************
# File: code39.py
# Based on postnet2.py originally 2006.03.06 Gregory Pittman
# this version 2010.08.05 © Gregory Pittman, 2010
# encodes numbers and letters, plus all other Code 39 characters
"""
Simple operation.
First dialog asks for your code (numbers and uppercase letters, plus space, period,
-,*,$,/,+,%) i.e., all characters allowed by Code 39, as many characters as you want.
Second dialog asks for height of bars in points.
Third dialog asks for the X-Pos and Y-Pos, separated only be whitespace, no comma!
Fourth dialog confirms that you want to print the characters underneath.
The start/stop character (*) is automatically added and does not show in the
human-readable sequence.
"""
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
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'])
# and these are for the rest
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_WARNING,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()
scribus.docChanged(1)
else:
scribus.messageBox('OOPS!','You must have a document open to run this script',scribus.ICON_WARNING,button1=scribus.BUTTON_OK)
sys.exit(1)
Line Positions
Something worth mentioning here is that the precise position of the endpoints of lines is in the middle of the line. Thus, when I was creating lines of a particular width with very specific spacing in between, I had to account for the width of the lines or otherwise they would encroach on the space, and so you see these weird arithmetic additions in the if/elif loops.
About Code39
Code 39 is a widely used code consisting of a series of narrow and wide black lines, alternating with narrow or wide white spaces. Each character is denoted by a sequence of 5 lines and 4 intervening spaces, with a narrow space in between characters. The digits 0-9 and capital letters A-Z, plus *, hyphen, period, $, /, % and space are defined. The * character is also known as the start/stop character, since all codes should begin and end with it to orient the scanner.
Narrow and wide lines, and narrow and wide spaces have corresponding width values, and the relative ratios are generally 1:2.2 to 1:3 (narrow:wide).