Initial commit: IT Site Survey AI v2 with all features
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
#Copyright ReportLab Europe Ltd. 2000-2026
|
||||
#see license.txt for license details
|
||||
__doc__="""The Reportlab PDF generation library."""
|
||||
Version = "5.0.0"
|
||||
__version__=Version
|
||||
__date__='20260618'
|
||||
|
||||
import sys, os
|
||||
|
||||
__min_python_version__ = (3,9)
|
||||
if sys.version_info< __min_python_version__:
|
||||
raise ImportError("""reportlab requires %s.%s+; other versions are unsupported.
|
||||
If you want to try with other python versions edit line 10 of reportlab/__init__
|
||||
to remove this error.""" % (__min_python_version__))
|
||||
|
||||
#define these early in reportlab's life
|
||||
def cmp(a,b):
|
||||
return -1 if a<b else (1 if a>b else 0)
|
||||
|
||||
def _fake_import(fn,name):
|
||||
from importlib.util import spec_from_loader, module_from_spec
|
||||
from importlib.machinery import SourceFileLoader
|
||||
spec = spec_from_loader(name, SourceFileLoader(name, fn))
|
||||
module = module_from_spec(spec)
|
||||
try:
|
||||
spec.loader.exec_module(module)
|
||||
except FileNotFoundError:
|
||||
raise ImportError('file %s not found' % ascii(fn))
|
||||
sys.modules[name] = module
|
||||
|
||||
#try to use dynamic modifications from
|
||||
#reportlab.local_rl_mods.py
|
||||
#reportlab_mods.py or ~/.reportlab_mods
|
||||
try:
|
||||
import reportlab.local_rl_mods
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
try:
|
||||
import reportlab_mods #application specific modifications can be anywhere on python path
|
||||
except ImportError:
|
||||
try:
|
||||
_fake_import(os.path.expanduser(os.path.join('~','.reportlab_mods')),'reportlab_mods')
|
||||
except (ImportError,KeyError,PermissionError):
|
||||
pass
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,8 @@
|
||||
This directory is a convenient place to put
|
||||
fonts where Reportlab will find them. If running
|
||||
in a server environment, this is a good place to
|
||||
put Type 1 fonts needed by your application. If
|
||||
in a desktop environment, you might prefer to add
|
||||
your font directories to the T1SearchPath in
|
||||
reportlab/rl_config.py instead.
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
2004-05-18 Michal Kosmulski <mkosmul@users.sourceforge.net>
|
||||
* Version 1.1
|
||||
* Changed license to GNU GPL with Font Exception
|
||||
* Added Zacute character
|
||||
* Added basic hinting
|
||||
* Added kerning information
|
||||
2000 Michal Kosmulski <mkosmul@users.sourceforge.net>
|
||||
* Version 1.0
|
||||
* Added Polish and German diacritic characters except for Zacute
|
||||
|
||||
1999 Michal Kosmulski <mkosmul@users.sourceforge.net>
|
||||
* Version 0.9
|
||||
* Includes only the 26 letters of the English alphabet
|
||||
* Distributed under a freeware license
|
||||
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
@@ -0,0 +1,26 @@
|
||||
Copyright (C) 1999, 2000, 2004 Michal Kosmulski
|
||||
<mkosmul@users.sourceforge.net>
|
||||
|
||||
This font 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 font 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 font; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
As a special exception, if you create a document which uses
|
||||
this font, and embed this font or unaltered portions of this font into
|
||||
the document, this font does not by itself cause the resulting
|
||||
document to be covered by the GNU General Public License. This
|
||||
exception does not however invalidate any other reasons why the
|
||||
document might be covered by the GNU General Public License. If you
|
||||
modify this font, you may extend this exception to your version of the
|
||||
font, but you are not obligated to do so. If you do not wish to do so,
|
||||
delete this exception statement from your version.
|
||||
@@ -0,0 +1,106 @@
|
||||
Dark Garden
|
||||
===========
|
||||
|
||||
|
||||
|
||||
GENERAL
|
||||
|
||||
Dark Garden is a decorative outline font of unusual shape. The typeface
|
||||
is based on author's original hand drawings. The letterform is complex,
|
||||
with all characters decorated with spikes resembling thorns or flames,
|
||||
character spacing is very dense. Such a theme makes it a great font for
|
||||
titles, banners, logos etc.
|
||||
|
||||
As of version 1.1, Dark Garden includes letters of the English alphabet,
|
||||
Polish and German diacritic characters and some punctuation. Unicode
|
||||
encoding is used. The font is equipped with hinting information to allow
|
||||
high quality rendering at small point sizes. Only horizontal and
|
||||
vertical hints are currently used, future versions might take advantage
|
||||
of truetype hinting instructions some day. There are also a lot of
|
||||
kerning pairs defined in the font - they were chosen after looking at a
|
||||
choice of Polish and English texts and selecting the character pairs
|
||||
that needed manual kerning.
|
||||
|
||||
The font was created with PfaEdit / FontForge
|
||||
(http://fontforge.sourceforge.net/) - an opensource font editing tool.
|
||||
Pfaedit uses its own text-based file format which can then be exported
|
||||
to truetype, postscript, opentype and many other font formats. This
|
||||
makes it possible to generate font files for Dark Garden in any of the
|
||||
many supported formats, so it can be used on almost any platform. So
|
||||
far, the truetype version has been tested on X11 (Linux) and Windows,
|
||||
the opentype version worked on Windows but not X11. Truetype should also
|
||||
work on Mac OS.
|
||||
|
||||
|
||||
|
||||
INSTALLATION
|
||||
|
||||
Installation is described for the truetype version of the font (which is
|
||||
what most users will need).
|
||||
|
||||
On Windows:
|
||||
* Extract .ttf files from the archive into a temporary directory
|
||||
* In the Control Panel choose Fonts
|
||||
* From the File menu choose Install New Font
|
||||
* Browse to the temporary directory you chose
|
||||
* "Dark Garden" should appear in the font list - click OK (this may
|
||||
require Administrator privileges)
|
||||
|
||||
On Linux / UNIX (using KDE):
|
||||
* Extract .ttf files from the archive into a temporary directory
|
||||
* In the Control Center choose Font Installer in the System
|
||||
Administration tree
|
||||
* Click on "Administrator Mode" and enter root's password
|
||||
* Click on "Add Fonts" icon
|
||||
* Select the .ttf file extracted from the archive and click OK
|
||||
|
||||
On Linux / UNIX (using commandline)
|
||||
unzip darkgarden-*.ttf.zip
|
||||
su
|
||||
ginstall -o root -m 644 DarkGardenMK.ttf /usr/X11R6/lib/fonts/TTF
|
||||
fc-cache -f
|
||||
|
||||
|
||||
|
||||
COPYRIGHT AND LICENSE
|
||||
|
||||
Copyright (C) 1999, 2000, 2004 Michal Kosmulski
|
||||
<mkosmul@users.sourceforge.net>
|
||||
|
||||
This font 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 font 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 font; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
As a special exception, if you create a document which uses
|
||||
this font, and embed this font or unaltered portions of this font into
|
||||
the document, this font does not by itself cause the resulting
|
||||
document to be covered by the GNU General Public License. This
|
||||
exception does not however invalidate any other reasons why the
|
||||
document might be covered by the GNU General Public License. If you
|
||||
modify this font, you may extend this exception to your version of the
|
||||
font, but you are not obligated to do so. If you do not wish to do so,
|
||||
delete this exception statement from your version.
|
||||
|
||||
The text of this license can be found in file COPYING.txt in the
|
||||
distribution archives. The GNU General Public License text can be found
|
||||
in file COPYING-GPL.txt.
|
||||
|
||||
|
||||
|
||||
CONTACTING THE AUTHOR
|
||||
|
||||
Send e-mail with questions, bug reports and patches to Michal Kosmulski,
|
||||
mkosmul@users.sourceforge.net
|
||||
|
||||
The homepage of Dark Garden Font is located at
|
||||
http://darkgarden.sourceforge.net/.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,429 @@
|
||||
StartFontMetrics 2.0
|
||||
Comment Generated by FontForge 20071110
|
||||
Comment Creation Date: Wed Sep 10 17:07:49 2008
|
||||
FontName DarkGardenMK
|
||||
FullName Dark Garden
|
||||
FamilyName Dark Garden
|
||||
Weight Medium
|
||||
Notice (Copyright (C) 1999, 2000, 2004 Michal Kosmulski )
|
||||
Comment <mkosmul@users.sourceforge.net>
|
||||
Comment
|
||||
Comment This font is free software; you can redistribute it and/or modify
|
||||
Comment it under the terms of the GNU General Public License as published by
|
||||
Comment the Free Software Foundation; either version 2 of the License, or
|
||||
Comment (at your option) any later version.
|
||||
Comment
|
||||
Comment This font is distributed in the hope that it will be useful,
|
||||
Comment but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
Comment MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
Comment GNU General Public License for more details.
|
||||
Comment
|
||||
Comment You should have received a copy of the GNU General Public License
|
||||
Comment along with this font; if not, write to the Free Software
|
||||
Comment Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
Comment
|
||||
Comment As a special exception, if you create a document which uses
|
||||
Comment this font, and embed this font or unaltered portions of this font into
|
||||
Comment the document, this font does not by itself cause the resulting
|
||||
Comment document to be covered by the GNU General Public License. This
|
||||
Comment exception does not however invalidate any other reasons why the
|
||||
Comment document might be covered by the GNU General Public License. If you
|
||||
Comment modify this font, you may extend this exception to your version of the
|
||||
Comment font, but you are not obligated to do so. If you do not wish to do so,
|
||||
Comment delete this exception statement from your version.
|
||||
Comment
|
||||
ItalicAngle 0
|
||||
IsFixedPitch false
|
||||
UnderlinePosition -420
|
||||
UnderlineThickness 80
|
||||
Version 1.1
|
||||
EncodingScheme ISO10646-1
|
||||
FontBBox -11 -331 935 1122
|
||||
CapHeight 931
|
||||
XHeight 869
|
||||
Ascender 831
|
||||
Descender -123
|
||||
StartCharMetrics 86
|
||||
C 0 ; WX 1000 ; N .notdef ; B 0 0 531 890 ;
|
||||
C 1 ; WX 0 ; N glyph1 ; B 0 0 0 0 ;
|
||||
C 2 ; WX 1000 ; N glyph2 ; B 0 0 0 0 ;
|
||||
C 32 ; WX 500 ; N space ; B 0 0 0 0 ;
|
||||
C 44 ; WX 130 ; N comma ; B 0 -76 123 105 ;
|
||||
C 45 ; WX 611 ; N hyphen ; B 46 364 560 519 ;
|
||||
C 46 ; WX 131 ; N period ; B 1 0 124 124 ;
|
||||
C 58 ; WX 187 ; N colon ; B 32 6 159 447 ;
|
||||
C 59 ; WX 187 ; N semicolon ; B 36 -98 163 470 ;
|
||||
C 65 ; WX 706 ; N A ; B 3 -162 670 853 ;
|
||||
C 66 ; WX 624 ; N B ; B -5 -27 602 911 ;
|
||||
C 67 ; WX 619 ; N C ; B -1 -52 590 846 ;
|
||||
C 68 ; WX 730 ; N D ; B 4 -133 703 912 ;
|
||||
C 69 ; WX 613 ; N E ; B 1 -100 613 836 ;
|
||||
C 70 ; WX 660 ; N F ; B 3 -96 629 833 ;
|
||||
C 71 ; WX 624 ; N G ; B 5 -61 594 898 ;
|
||||
C 72 ; WX 660 ; N H ; B 7 -177 629 876 ;
|
||||
C 73 ; WX 284 ; N I ; B 22 -179 271 932 ;
|
||||
C 74 ; WX 603 ; N J ; B 3 -93 570 863 ;
|
||||
C 75 ; WX 639 ; N K ; B 7 -182 625 921 ;
|
||||
C 76 ; WX 658 ; N L ; B 15 -3 616 903 ;
|
||||
C 77 ; WX 833 ; N M ; B 9 -236 861 874 ;
|
||||
C 78 ; WX 614 ; N N ; B 3 -135 579 917 ;
|
||||
C 79 ; WX 691 ; N O ; B 9 -35 659 848 ;
|
||||
C 80 ; WX 648 ; N P ; B 4 -203 605 846 ;
|
||||
C 81 ; WX 612 ; N Q ; B -11 -179 578 894 ;
|
||||
C 82 ; WX 647 ; N R ; B -1 -331 614 891 ;
|
||||
C 83 ; WX 666 ; N S ; B 3 -60 654 876 ;
|
||||
C 84 ; WX 829 ; N T ; B 0 -195 787 817 ;
|
||||
C 85 ; WX 688 ; N U ; B 6 -33 656 874 ;
|
||||
C 86 ; WX 618 ; N V ; B 4 -188 589 991 ;
|
||||
C 87 ; WX 985 ; N W ; B 4 -132 935 974 ;
|
||||
C 88 ; WX 690 ; N X ; B 6 -125 731 951 ;
|
||||
C 89 ; WX 645 ; N Y ; B 7 -209 609 953 ;
|
||||
C 90 ; WX 841 ; N Z ; B 14 -108 853 845 ;
|
||||
C 97 ; WX 612 ; N a ; B 13 -93 581 769 ;
|
||||
C 98 ; WX 528 ; N b ; B -4 -23 512 774 ;
|
||||
C 99 ; WX 571 ; N c ; B 42 15 545 779 ;
|
||||
C 100 ; WX 641 ; N d ; B 15 -60 609 829 ;
|
||||
C 101 ; WX 527 ; N e ; B 8 -35 528 760 ;
|
||||
C 102 ; WX 563 ; N f ; B 21 -25 553 765 ;
|
||||
C 103 ; WX 549 ; N g ; B 21 10 522 825 ;
|
||||
C 104 ; WX 581 ; N h ; B 24 -96 553 798 ;
|
||||
C 105 ; WX 256 ; N i ; B 22 -99 235 846 ;
|
||||
C 106 ; WX 527 ; N j ; B 17 -27 499 786 ;
|
||||
C 107 ; WX 543 ; N k ; B 6 -155 531 783 ;
|
||||
C 108 ; WX 525 ; N l ; B -1 62 510 832 ;
|
||||
C 109 ; WX 718 ; N m ; B 14 -151 738 792 ;
|
||||
C 110 ; WX 523 ; N n ; B 13 -63 502 832 ;
|
||||
C 111 ; WX 612 ; N o ; B 30 28 584 779 ;
|
||||
C 112 ; WX 561 ; N p ; B 13 -124 524 767 ;
|
||||
C 113 ; WX 566 ; N q ; B 33 -98 535 814 ;
|
||||
C 114 ; WX 548 ; N r ; B -3 -245 520 795 ;
|
||||
C 115 ; WX 567 ; N s ; B 3 9 556 806 ;
|
||||
C 116 ; WX 718 ; N t ; B 13 -117 682 743 ;
|
||||
C 117 ; WX 587 ; N u ; B 8 36 560 805 ;
|
||||
C 118 ; WX 530 ; N v ; B 9 -99 506 902 ;
|
||||
C 119 ; WX 774 ; N w ; B 1 -49 793 891 ;
|
||||
C 120 ; WX 604 ; N x ; B 11 -43 628 870 ;
|
||||
C 121 ; WX 559 ; N y ; B 14 -122 526 866 ;
|
||||
C 122 ; WX 764 ; N z ; B 7 -36 720 774 ;
|
||||
C 196 ; WX 765 ; N Adieresis ; B 8 -179 724 1064 ;
|
||||
C 211 ; WX 704 ; N Oacute ; B 7 -82 665 1012 ;
|
||||
C 214 ; WX 791 ; N Odieresis ; B 1 -68 755 1084 ;
|
||||
C 220 ; WX 763 ; N Udieresis ; B -1 -59 728 1122 ;
|
||||
C 223 ; WX 543 ; N germandbls ; B 2 -304 516 795 ;
|
||||
C 228 ; WX 650 ; N adieresis ; B 6 -152 615 904 ;
|
||||
C 243 ; WX 600 ; N oacute ; B 8 -2 567 928 ;
|
||||
C 246 ; WX 672 ; N odieresis ; B 0 -58 642 921 ;
|
||||
C 252 ; WX 648 ; N udieresis ; B -1 -50 619 953 ;
|
||||
C -1 ; WX 699 ; N Aogonek ; B 1 -257 657 838 ;
|
||||
C -1 ; WX 594 ; N aogonek ; B 1 -219 559 712 ;
|
||||
C -1 ; WX 596 ; N Cacute ; B 8 -57 561 1046 ;
|
||||
C -1 ; WX 514 ; N cacute ; B 14 20 484 959 ;
|
||||
C -1 ; WX 739 ; N Eogonek ; B 2 -240 738 785 ;
|
||||
C -1 ; WX 637 ; N eogonek ; B 13 -121 640 750 ;
|
||||
C -1 ; WX 848 ; N Lslash ; B 8 -107 908 871 ;
|
||||
C -1 ; WX 722 ; N lslash ; B 11 -32 776 799 ;
|
||||
C -1 ; WX 627 ; N Nacute ; B 8 -46 597 1050 ;
|
||||
C -1 ; WX 534 ; N nacute ; B 8 32 509 964 ;
|
||||
C -1 ; WX 558 ; N Sacute ; B 4 -27 566 1094 ;
|
||||
C -1 ; WX 490 ; N sacute ; B 7 58 485 1010 ;
|
||||
C -1 ; WX 721 ; N Zacute ; B 7 -90 714 1013 ;
|
||||
C -1 ; WX 617 ; N zacute ; B 7 -44 607 894 ;
|
||||
C -1 ; WX 759 ; N Zdotaccent ; B -7 -103 749 925 ;
|
||||
C -1 ; WX 655 ; N zdotaccent ; B 4 -53 645 822 ;
|
||||
EndCharMetrics
|
||||
StartKernData
|
||||
StartKernPairs 291
|
||||
KPX hyphen Z -126
|
||||
KPX hyphen z -101
|
||||
KPX hyphen X -88
|
||||
KPX hyphen x -76
|
||||
KPX hyphen Y -63
|
||||
KPX hyphen y -50
|
||||
KPX hyphen W -88
|
||||
KPX hyphen w -88
|
||||
KPX hyphen T -139
|
||||
KPX hyphen t -133
|
||||
KPX hyphen S -114
|
||||
KPX hyphen s -76
|
||||
KPX hyphen A -114
|
||||
KPX hyphen a -114
|
||||
KPX A C -25
|
||||
KPX A c -63
|
||||
KPX A M -50
|
||||
KPX A m -38
|
||||
KPX A h -63
|
||||
KPX A H -50
|
||||
KPX A hyphen -82
|
||||
KPX A s -139
|
||||
KPX A S -120
|
||||
KPX A y -145
|
||||
KPX A Y -125
|
||||
KPX A t -145
|
||||
KPX A T -145
|
||||
KPX A v -31
|
||||
KPX A w -112
|
||||
KPX A V -24
|
||||
KPX A W -94
|
||||
KPX C S -69
|
||||
KPX C s -63
|
||||
KPX C A -31
|
||||
KPX C a -44
|
||||
KPX D Z -88
|
||||
KPX D z -69
|
||||
KPX D a -101
|
||||
KPX D A -73
|
||||
KPX E S -63
|
||||
KPX E s -63
|
||||
KPX F t -139
|
||||
KPX F T -82
|
||||
KPX F hyphen -101
|
||||
KPX F period -114
|
||||
KPX F comma -133
|
||||
KPX F A -239
|
||||
KPX F a -229
|
||||
KPX H A -44
|
||||
KPX K o -50
|
||||
KPX K O -25
|
||||
KPX K s -107
|
||||
KPX K S -101
|
||||
KPX K g -88
|
||||
KPX K G -38
|
||||
KPX K c -114
|
||||
KPX K C -69
|
||||
KPX L t -203
|
||||
KPX L T -203
|
||||
KPX L Y -114
|
||||
KPX L y -114
|
||||
KPX L i -63
|
||||
KPX L I -69
|
||||
KPX L hyphen -107
|
||||
KPX L S -114
|
||||
KPX L w -133
|
||||
KPX L W -139
|
||||
KPX M A -50
|
||||
KPX M a -50
|
||||
KPX M i 38
|
||||
KPX N A -114
|
||||
KPX N a -101
|
||||
KPX O y -38
|
||||
KPX O Y -44
|
||||
KPX O a -76
|
||||
KPX O A -76
|
||||
KPX O x -76
|
||||
KPX O X -76
|
||||
KPX O W -114
|
||||
KPX O t -139
|
||||
KPX O T -178
|
||||
KPX P hyphen -101
|
||||
KPX P period -126
|
||||
KPX P comma -139
|
||||
KPX P t -44
|
||||
KPX P T -95
|
||||
KPX P Lslash -177
|
||||
KPX P lslash -177
|
||||
KPX P A -166
|
||||
KPX P a -177
|
||||
KPX R Y -69
|
||||
KPX R y -63
|
||||
KPX R S -101
|
||||
KPX R G -50
|
||||
KPX R t -139
|
||||
KPX R T -152
|
||||
KPX R V -10
|
||||
KPX R W -73
|
||||
KPX S E 25
|
||||
KPX S e 19
|
||||
KPX S S -57
|
||||
KPX S t -88
|
||||
KPX S T -31
|
||||
KPX T lslash -190
|
||||
KPX T Lslash -229
|
||||
KPX T U -57
|
||||
KPX T u -69
|
||||
KPX T h -114
|
||||
KPX T H -76
|
||||
KPX T hyphen -146
|
||||
KPX T period -126
|
||||
KPX T comma -126
|
||||
KPX T oacute -146
|
||||
KPX T Oacute -101
|
||||
KPX T s -139
|
||||
KPX T S -126
|
||||
KPX T o -101
|
||||
KPX T O -69
|
||||
KPX T A -250
|
||||
KPX T a -250
|
||||
KPX U t -38
|
||||
KPX U T -31
|
||||
KPX U X -63
|
||||
KPX V Odieresis -94
|
||||
KPX V odieresis -109
|
||||
KPX V o -95
|
||||
KPX V O -76
|
||||
KPX V hyphen -101
|
||||
KPX V period -120
|
||||
KPX V comma -120
|
||||
KPX V I -50
|
||||
KPX V i -88
|
||||
KPX V a -156
|
||||
KPX V A -131
|
||||
KPX W Odieresis -87
|
||||
KPX W odieresis -103
|
||||
KPX W lslash -229
|
||||
KPX W Lslash -248
|
||||
KPX W H -126
|
||||
KPX W h -146
|
||||
KPX W hyphen -114
|
||||
KPX W period -159
|
||||
KPX W comma -177
|
||||
KPX W s -159
|
||||
KPX W S -126
|
||||
KPX W i -88
|
||||
KPX W I -44
|
||||
KPX W oacute -152
|
||||
KPX W Oacute -178
|
||||
KPX W o -133
|
||||
KPX W O -107
|
||||
KPX W Adieresis -152
|
||||
KPX W adieresis -131
|
||||
KPX W aogonek -166
|
||||
KPX W Aogonek -166
|
||||
KPX W a -219
|
||||
KPX W A -194
|
||||
KPX X hyphen -101
|
||||
KPX Y O -44
|
||||
KPX Y o -88
|
||||
KPX Y Lslash -152
|
||||
KPX Y S -126
|
||||
KPX Y hyphen -95
|
||||
KPX Y period -114
|
||||
KPX Y comma -114
|
||||
KPX Y a -208
|
||||
KPX Y A -187
|
||||
KPX Z y -57
|
||||
KPX Z Y -50
|
||||
KPX Z lslash -88
|
||||
KPX Z Lslash -82
|
||||
KPX Z i -25
|
||||
KPX Z I -31
|
||||
KPX Z e -31
|
||||
KPX Z b -38
|
||||
KPX Z B -38
|
||||
KPX Z hyphen -101
|
||||
KPX a c -63
|
||||
KPX a m -38
|
||||
KPX a h -57
|
||||
KPX a hyphen -88
|
||||
KPX a s -101
|
||||
KPX a y -145
|
||||
KPX a t -166
|
||||
KPX a v -20
|
||||
KPX a w -107
|
||||
KPX c s -57
|
||||
KPX c a -50
|
||||
KPX d z -44
|
||||
KPX d a -73
|
||||
KPX e s -38
|
||||
KPX f t -63
|
||||
KPX f hyphen -76
|
||||
KPX f period -120
|
||||
KPX f comma -126
|
||||
KPX f a -208
|
||||
KPX h a -50
|
||||
KPX k o -31
|
||||
KPX k s -50
|
||||
KPX k g -31
|
||||
KPX k c -76
|
||||
KPX l t -139
|
||||
KPX l y -76
|
||||
KPX l i -38
|
||||
KPX l hyphen -76
|
||||
KPX l s -63
|
||||
KPX l w -95
|
||||
KPX m a -44
|
||||
KPX m i 31
|
||||
KPX n a -101
|
||||
KPX o y -31
|
||||
KPX o a -76
|
||||
KPX o x -69
|
||||
KPX o w -95
|
||||
KPX o t -152
|
||||
KPX p hyphen -50
|
||||
KPX p period -107
|
||||
KPX p comma -101
|
||||
KPX p t -95
|
||||
KPX p lslash -145
|
||||
KPX p a -145
|
||||
KPX r y -76
|
||||
KPX r s -88
|
||||
KPX r g -50
|
||||
KPX r t -165
|
||||
KPX r v -20
|
||||
KPX r w -73
|
||||
KPX s c -25
|
||||
KPX s s -50
|
||||
KPX s t -38
|
||||
KPX t lslash -159
|
||||
KPX t u -57
|
||||
KPX t h -82
|
||||
KPX t hyphen -107
|
||||
KPX t period -126
|
||||
KPX t comma -126
|
||||
KPX t oacute -101
|
||||
KPX t s -101
|
||||
KPX t o -88
|
||||
KPX t a -218
|
||||
KPX u t -38
|
||||
KPX u x -50
|
||||
KPX v odieresis -83
|
||||
KPX v o -69
|
||||
KPX v hyphen -88
|
||||
KPX v period -88
|
||||
KPX v comma -101
|
||||
KPX v i -50
|
||||
KPX v a -125
|
||||
KPX w odieresis -20
|
||||
KPX w lslash -146
|
||||
KPX w h -50
|
||||
KPX w hyphen -57
|
||||
KPX w period -95
|
||||
KPX w comma -101
|
||||
KPX w s -44
|
||||
KPX w i 6
|
||||
KPX w oacute -76
|
||||
KPX w o -44
|
||||
KPX w adieresis -111
|
||||
KPX w aogonek -152
|
||||
KPX w a -166
|
||||
KPX x hyphen -101
|
||||
KPX y o -63
|
||||
KPX y lslash -126
|
||||
KPX y s -101
|
||||
KPX y hyphen -82
|
||||
KPX y period -95
|
||||
KPX y comma -101
|
||||
KPX y a -177
|
||||
KPX z y -95
|
||||
KPX z lslash -120
|
||||
KPX z i -69
|
||||
KPX z e -50
|
||||
KPX z b -76
|
||||
KPX z hyphen -177
|
||||
KPX Oacute T -139
|
||||
KPX Oacute W -88
|
||||
KPX germandbls t -95
|
||||
KPX germandbls T -152
|
||||
KPX oacute t -114
|
||||
KPX oacute w -76
|
||||
KPX Aogonek W -101
|
||||
KPX aogonek w -88
|
||||
KPX Lslash Y -76
|
||||
KPX Lslash y -38
|
||||
KPX Lslash T -101
|
||||
KPX Lslash W -156
|
||||
KPX lslash y -50
|
||||
KPX lslash t -101
|
||||
KPX lslash w -187
|
||||
EndKernPairs
|
||||
EndKernData
|
||||
EndFontMetrics
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,124 @@
|
||||
Bitstream Vera Fonts Copyright
|
||||
|
||||
The fonts have a generous copyright, allowing derivative works (as
|
||||
long as "Bitstream" or "Vera" are not in the names), and full
|
||||
redistribution (so long as they are not *sold* by themselves). They
|
||||
can be be bundled, redistributed and sold with any software.
|
||||
|
||||
The fonts are distributed under the following copyright:
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream
|
||||
Vera is a trademark of Bitstream, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the fonts accompanying this license ("Fonts") and associated
|
||||
documentation files (the "Font Software"), to reproduce and distribute
|
||||
the Font Software, including without limitation the rights to use,
|
||||
copy, merge, publish, distribute, and/or sell copies of the Font
|
||||
Software, and to permit persons to whom the Font Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice
|
||||
shall be included in all copies of one or more of the Font Software
|
||||
typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in
|
||||
particular the designs of glyphs or characters in the Fonts may be
|
||||
modified and additional glyphs or characters may be added to the
|
||||
Fonts, only if the fonts are renamed to names not containing either
|
||||
the words "Bitstream" or the word "Vera".
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts
|
||||
or Font Software that has been modified and is distributed under the
|
||||
"Bitstream Vera" names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but
|
||||
no copy of one or more of the Font Software typefaces may be sold by
|
||||
itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
|
||||
BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
|
||||
OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT
|
||||
SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of Gnome, the Gnome
|
||||
Foundation, and Bitstream Inc., shall not be used in advertising or
|
||||
otherwise to promote the sale, use or other dealings in this Font
|
||||
Software without prior written authorization from the Gnome Foundation
|
||||
or Bitstream Inc., respectively. For further information, contact:
|
||||
fonts at gnome dot org.
|
||||
|
||||
Copyright FAQ
|
||||
=============
|
||||
|
||||
1. I don't understand the resale restriction... What gives?
|
||||
|
||||
Bitstream is giving away these fonts, but wishes to ensure its
|
||||
competitors can't just drop the fonts as is into a font sale system
|
||||
and sell them as is. It seems fair that if Bitstream can't make money
|
||||
from the Bitstream Vera fonts, their competitors should not be able to
|
||||
do so either. You can sell the fonts as part of any software package,
|
||||
however.
|
||||
|
||||
2. I want to package these fonts separately for distribution and
|
||||
sale as part of a larger software package or system. Can I do so?
|
||||
|
||||
Yes. A RPM or Debian package is a "larger software package" to begin
|
||||
with, and you aren't selling them independently by themselves.
|
||||
See 1. above.
|
||||
|
||||
3. Are derivative works allowed?
|
||||
Yes!
|
||||
|
||||
4. Can I change or add to the font(s)?
|
||||
Yes, but you must change the name(s) of the font(s).
|
||||
|
||||
5. Under what terms are derivative works allowed?
|
||||
|
||||
You must change the name(s) of the fonts. This is to ensure the
|
||||
quality of the fonts, both to protect Bitstream and Gnome. We want to
|
||||
ensure that if an application has opened a font specifically of these
|
||||
names, it gets what it expects (though of course, using fontconfig,
|
||||
substitutions could still could have occurred during font
|
||||
opening). You must include the Bitstream copyright. Additional
|
||||
copyrights can be added, as per copyright law. Happy Font Hacking!
|
||||
|
||||
6. If I have improvements for Bitstream Vera, is it possible they might get
|
||||
adopted in future versions?
|
||||
|
||||
Yes. The contract between the Gnome Foundation and Bitstream has
|
||||
provisions for working with Bitstream to ensure quality additions to
|
||||
the Bitstream Vera font family. Please contact us if you have such
|
||||
additions. Note, that in general, we will want such additions for the
|
||||
entire family, not just a single font, and that you'll have to keep
|
||||
both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add
|
||||
glyphs to the font, they must be stylistically in keeping with Vera's
|
||||
design. Vera cannot become a "ransom note" font. Jim Lyles will be
|
||||
providing a document describing the design elements used in Vera, as a
|
||||
guide and aid for people interested in contributing to Vera.
|
||||
|
||||
7. I want to sell a software package that uses these fonts: Can I do so?
|
||||
|
||||
Sure. Bundle the fonts with your software and sell your software
|
||||
with the fonts. That is the intent of the copyright.
|
||||
|
||||
8. If applications have built the names "Bitstream Vera" into them,
|
||||
can I override this somehow to use fonts of my choosing?
|
||||
|
||||
This depends on exact details of the software. Most open source
|
||||
systems and software (e.g., Gnome, KDE, etc.) are now converting to
|
||||
use fontconfig (see www.fontconfig.org) to handle font configuration,
|
||||
selection and substitution; it has provisions for overriding font
|
||||
names and subsituting alternatives. An example is provided by the
|
||||
supplied local.conf file, which chooses the family Bitstream Vera for
|
||||
"sans", "serif" and "monospace". Other software (e.g., the XFree86
|
||||
core server) has other mechanisms for font substitution.
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
StartFontMetrics 2.0
|
||||
Comment Generated by FontForge 20110222
|
||||
Comment Creation Date: Sun Oct 16 04:57:33 2011
|
||||
FontName CALLIG15
|
||||
FullName CALLIG15
|
||||
FamilyName CALLIG15
|
||||
Weight Medium
|
||||
Notice (Copyright 1992 Peter Vanroose, 1999 S. Dachian)
|
||||
Comment You may freely use, modify and/or distribute this file, as long as this copyright notice is retained
|
||||
ItalicAngle 0
|
||||
IsFixedPitch false
|
||||
UnderlinePosition -67
|
||||
UnderlineThickness 33
|
||||
Version 001.000
|
||||
EncodingScheme FontSpecific
|
||||
FontBBox -294 -257 1566 839
|
||||
CapHeight 634
|
||||
XHeight 226
|
||||
Ascender 452
|
||||
Descender -221
|
||||
StartCharMetrics 168
|
||||
C 0 ; WX 143 ; N grave ; B 30 744 113 831 ;
|
||||
C 1 ; WX 144 ; N acute ; B 30 239 114 319 ;
|
||||
C 2 ; WX 153 ; N circumflex ; B 164 239 348 319 ;
|
||||
C 3 ; WX 140 ; N tilde ; B 167 239 306 278 ;
|
||||
C 4 ; WX 170 ; N dieresis ; B 30 239 139 289 ;
|
||||
C 6 ; WX 118 ; N ring ; B 195 239 296 335 ;
|
||||
C 8 ; WX 158 ; N breve ; B 176 249 360 330 ;
|
||||
C 10 ; WX 59 ; N dotaccent ; B 208 287 253 332 ;
|
||||
C 14 ; WX 142 ; N guilsinglleft ; B 70 0 195 187 ;
|
||||
C 15 ; WX 142 ; N guilsinglright ; B 63 0 190 182 ;
|
||||
C 16 ; WX 165 ; N quotedblleft ; B 400 580 587 664 ;
|
||||
C 17 ; WX 164 ; N quotedblright ; B 387 580 573 664 ;
|
||||
C 18 ; WX 170 ; N quotedblbase ; B -17 -46 169 40 ;
|
||||
C 19 ; WX 230 ; N guillemotleft ; B 69 0 289 187 ;
|
||||
C 20 ; WX 231 ; N guillemotright ; B 63 0 283 187 ;
|
||||
C 22 ; WX 1099 ; N emdash ; B 58 90 1187 141 ;
|
||||
C 28 ; WX 336 ; N fi ; B -187 -231 626 523 ;
|
||||
C 29 ; WX 394 ; N fl ; B -188 -231 811 523 ;
|
||||
C 33 ; WX 206 ; N exclam ; B 40 -7 392 341 ;
|
||||
C 34 ; WX 193 ; N quotedbl ; B 425 557 563 664 ;
|
||||
C 35 ; WX 188 ; N numbersign ; B 68 -7 241 190 ;
|
||||
C 36 ; WX 559 ; N dollar ; B 151 -83 759 666 ;
|
||||
C 37 ; WX 388 ; N percent ; B 132 -7 460 328 ;
|
||||
C 38 ; WX 379 ; N ampersand ; B -83 -223 473 296 ;
|
||||
C 39 ; WX 78 ; N quoteright ; B 388 580 485 664 ;
|
||||
C 40 ; WX 191 ; N parenleft ; B 57 -7 484 459 ;
|
||||
C 41 ; WX 193 ; N parenright ; B -2 -7 427 457 ;
|
||||
C 42 ; WX 239 ; N asterisk ; B 373 465 603 665 ;
|
||||
C 44 ; WX 129 ; N comma ; B 21 -25 119 60 ;
|
||||
C 45 ; WX 140 ; N hyphen ; B 68 80 192 115 ;
|
||||
C 46 ; WX 141 ; N period ; B 40 -7 101 55 ;
|
||||
C 47 ; WX 149 ; N slash ; B 12 -7 350 329 ;
|
||||
C 48 ; WX 298 ; N zero ; B 82 -7 439 323 ;
|
||||
C 49 ; WX 244 ; N one ; B 80 0 437 330 ;
|
||||
C 50 ; WX 318 ; N two ; B 30 -9 398 326 ;
|
||||
C 51 ; WX 312 ; N three ; B 60 -7 459 340 ;
|
||||
C 52 ; WX 333 ; N four ; B 84 0 419 334 ;
|
||||
C 53 ; WX 296 ; N five ; B 58 -6 479 331 ;
|
||||
C 54 ; WX 279 ; N six ; B 80 -7 446 335 ;
|
||||
C 55 ; WX 302 ; N seven ; B 89 1 483 331 ;
|
||||
C 56 ; WX 294 ; N eight ; B 78 -7 438 328 ;
|
||||
C 57 ; WX 269 ; N nine ; B 36 -7 402 328 ;
|
||||
C 58 ; WX 142 ; N colon ; B 40 -7 215 175 ;
|
||||
C 59 ; WX 119 ; N semicolon ; B 0 -25 188 174 ;
|
||||
C 63 ; WX 274 ; N question ; B 27 -7 415 305 ;
|
||||
C 65 ; WX 789 ; N A ; B 85 -6 1286 666 ;
|
||||
C 66 ; WX 884 ; N B ; B 160 -7 1179 674 ;
|
||||
C 67 ; WX 774 ; N C ; B 323 -7 1124 663 ;
|
||||
C 68 ; WX 888 ; N D ; B 202 -6 1128 659 ;
|
||||
C 69 ; WX 723 ; N E ; B 337 -7 1027 703 ;
|
||||
C 70 ; WX 673 ; N F ; B 72 -6 1242 666 ;
|
||||
C 71 ; WX 943 ; N G ; B 306 -210 1255 669 ;
|
||||
C 72 ; WX 795 ; N H ; B 135 -7 1304 660 ;
|
||||
C 73 ; WX 599 ; N I ; B 71 -7 1102 651 ;
|
||||
C 74 ; WX 365 ; N J ; B -120 -257 870 651 ;
|
||||
C 75 ; WX 792 ; N K ; B 85 -7 1339 656 ;
|
||||
C 76 ; WX 736 ; N L ; B 83 -6 1167 671 ;
|
||||
C 77 ; WX 799 ; N M ; B 55 -7 1184 669 ;
|
||||
C 78 ; WX 933 ; N N ; B 75 -6 1474 656 ;
|
||||
C 79 ; WX 586 ; N O ; B 136 -7 934 668 ;
|
||||
C 80 ; WX 766 ; N P ; B 132 -7 1110 655 ;
|
||||
C 81 ; WX 602 ; N Q ; B 135 -9 949 643 ;
|
||||
C 82 ; WX 866 ; N R ; B 162 -7 1125 668 ;
|
||||
C 83 ; WX 704 ; N S ; B 122 -7 1126 667 ;
|
||||
C 84 ; WX 628 ; N T ; B 72 -7 1243 668 ;
|
||||
C 85 ; WX 765 ; N U ; B 316 -4 1155 654 ;
|
||||
C 86 ; WX 815 ; N V ; B 353 -7 1363 677 ;
|
||||
C 87 ; WX 1025 ; N W ; B 355 -10 1566 659 ;
|
||||
C 88 ; WX 664 ; N X ; B 62 -6 1181 662 ;
|
||||
C 89 ; WX 692 ; N Y ; B 260 -7 1080 645 ;
|
||||
C 90 ; WX 679 ; N Z ; B 159 -7 1009 634 ;
|
||||
C 91 ; WX 590 ; N bracketleft ; B 30 -1 558 464 ;
|
||||
C 93 ; WX 623 ; N bracketright ; B 30 -1 591 467 ;
|
||||
C 94 ; WX 373 ; N asciicircum ; B 30 448 342 664 ;
|
||||
C 95 ; WX 1032 ; N underscore ; B 0 -100 1028 -47 ;
|
||||
C 96 ; WX 76 ; N quoteleft ; B 400 580 498 664 ;
|
||||
C 97 ; WX 293 ; N a ; B 45 -5 358 193 ;
|
||||
C 98 ; WX 291 ; N b ; B 62 -7 615 533 ;
|
||||
C 99 ; WX 190 ; N c ; B 46 -6 257 195 ;
|
||||
C 100 ; WX 299 ; N d ; B 42 -7 616 452 ;
|
||||
C 101 ; WX 195 ; N e ; B 41 -7 261 191 ;
|
||||
C 102 ; WX 216 ; N f ; B -181 -231 632 523 ;
|
||||
C 103 ; WX 296 ; N g ; B -145 -229 362 197 ;
|
||||
C 104 ; WX 352 ; N h ; B 28 -6 636 520 ;
|
||||
C 105 ; WX 150 ; N i ; B 41 -7 331 332 ;
|
||||
C 106 ; WX 156 ; N j ; B -294 -228 317 331 ;
|
||||
C 107 ; WX 315 ; N k ; B 36 0 630 534 ;
|
||||
C 108 ; WX 189 ; N l ; B 64 -7 608 523 ;
|
||||
C 109 ; WX 525 ; N m ; B 57 0 589 196 ;
|
||||
C 110 ; WX 361 ; N n ; B 59 -1 426 193 ;
|
||||
C 111 ; WX 218 ; N o ; B 41 -7 283 191 ;
|
||||
C 112 ; WX 332 ; N p ; B -208 -225 397 322 ;
|
||||
C 113 ; WX 284 ; N q ; B -82 -217 357 193 ;
|
||||
C 114 ; WX 214 ; N r ; B 63 -7 279 228 ;
|
||||
C 115 ; WX 165 ; N s ; B 12 -7 227 243 ;
|
||||
C 116 ; WX 186 ; N t ; B 60 -6 360 335 ;
|
||||
C 117 ; WX 310 ; N u ; B 41 -7 375 190 ;
|
||||
C 118 ; WX 305 ; N v ; B 64 -7 373 193 ;
|
||||
C 119 ; WX 460 ; N w ; B 64 -7 524 202 ;
|
||||
C 120 ; WX 274 ; N x ; B 30 -7 339 195 ;
|
||||
C 121 ; WX 351 ; N y ; B -89 -222 415 190 ;
|
||||
C 122 ; WX 289 ; N z ; B 64 -12 354 192 ;
|
||||
C 123 ; WX 312 ; N braceleft ; B 40 1 490 464 ;
|
||||
C 125 ; WX 532 ; N braceright ; B 40 -1 490 461 ;
|
||||
C 126 ; WX 402 ; N asciitilde ; B 30 192 371 307 ;
|
||||
C 127 ; WX 140 ; N sfthyphen ; B 68 80 192 115 ;
|
||||
C 152 ; WX 740 ; N Ydieresis ; B 260 -7 1080 794 ;
|
||||
C 184 ; WX 358 ; N ydieresis ; B -82 -222 423 299 ;
|
||||
C 189 ; WX 158 ; N exclamdown ; B -86 -141 266 206 ;
|
||||
C 190 ; WX 265 ; N questiondown ; B -15 -106 373 206 ;
|
||||
C 191 ; WX 773 ; N sterling ; B 67 -10 1003 480 ;
|
||||
C 192 ; WX 787 ; N Agrave ; B 83 -6 1334 826 ;
|
||||
C 193 ; WX 792 ; N Aacute ; B 88 -6 1340 824 ;
|
||||
C 194 ; WX 789 ; N Acircumflex ; B 85 -6 1357 824 ;
|
||||
C 195 ; WX 791 ; N Atilde ; B 86 -6 1318 783 ;
|
||||
C 196 ; WX 793 ; N Adieresis ; B 88 -6 1319 794 ;
|
||||
C 197 ; WX 792 ; N Aring ; B 86 -6 1326 839 ;
|
||||
C 198 ; WX 1226 ; N AE ; B 77 -6 1554 679 ;
|
||||
C 199 ; WX 780 ; N Ccedilla ; B 314 -115 1131 663 ;
|
||||
C 200 ; WX 684 ; N Egrave ; B 335 -7 1025 831 ;
|
||||
C 201 ; WX 685 ; N Eacute ; B 336 -7 1029 824 ;
|
||||
C 202 ; WX 681 ; N Ecircumflex ; B 334 -7 1084 824 ;
|
||||
C 203 ; WX 682 ; N Edieresis ; B 335 -7 1025 794 ;
|
||||
C 204 ; WX 597 ; N Igrave ; B 68 -7 1099 831 ;
|
||||
C 205 ; WX 598 ; N Iacute ; B 69 -7 1100 824 ;
|
||||
C 206 ; WX 597 ; N Icircumflex ; B 68 -7 1114 824 ;
|
||||
C 207 ; WX 597 ; N Idieresis ; B 68 -7 1099 794 ;
|
||||
C 209 ; WX 1112 ; N Ntilde ; B 73 -6 1472 783 ;
|
||||
C 210 ; WX 586 ; N Ograve ; B 135 -7 933 831 ;
|
||||
C 211 ; WX 586 ; N Oacute ; B 136 -7 934 824 ;
|
||||
C 212 ; WX 586 ; N Ocircumflex ; B 136 -7 937 824 ;
|
||||
C 213 ; WX 587 ; N Otilde ; B 136 -7 934 783 ;
|
||||
C 214 ; WX 586 ; N Odieresis ; B 135 -7 933 794 ;
|
||||
C 215 ; WX 1306 ; N OE ; B 73 -7 1234 704 ;
|
||||
C 216 ; WX 608 ; N Oslash ; B 132 -7 954 699 ;
|
||||
C 217 ; WX 764 ; N Ugrave ; B 316 -4 1155 831 ;
|
||||
C 218 ; WX 765 ; N Uacute ; B 316 -4 1155 824 ;
|
||||
C 219 ; WX 764 ; N Ucircumflex ; B 316 -4 1155 824 ;
|
||||
C 220 ; WX 764 ; N Udieresis ; B 316 -4 1155 794 ;
|
||||
C 224 ; WX 295 ; N agrave ; B 47 -5 360 326 ;
|
||||
C 225 ; WX 296 ; N aacute ; B 48 -5 362 319 ;
|
||||
C 226 ; WX 295 ; N acircumflex ; B 47 -5 416 319 ;
|
||||
C 227 ; WX 295 ; N atilde ; B 47 -5 372 278 ;
|
||||
C 228 ; WX 295 ; N adieresis ; B 47 -5 360 289 ;
|
||||
C 229 ; WX 296 ; N aring ; B 45 -5 367 335 ;
|
||||
C 230 ; WX 357 ; N ae ; B 43 -6 422 193 ;
|
||||
C 231 ; WX 200 ; N ccedilla ; B -64 -129 265 200 ;
|
||||
C 232 ; WX 198 ; N egrave ; B 43 -7 263 326 ;
|
||||
C 233 ; WX 199 ; N eacute ; B 44 -7 280 319 ;
|
||||
C 234 ; WX 198 ; N ecircumflex ; B 43 -7 333 319 ;
|
||||
C 235 ; WX 197 ; N edieresis ; B 43 -7 273 289 ;
|
||||
C 236 ; WX 151 ; N igrave ; B 42 -7 221 326 ;
|
||||
C 237 ; WX 150 ; N iacute ; B 41 -7 259 319 ;
|
||||
C 238 ; WX 150 ; N icircumflex ; B 41 -7 318 319 ;
|
||||
C 239 ; WX 150 ; N idieresis ; B 41 -7 246 289 ;
|
||||
C 241 ; WX 362 ; N ntilde ; B 58 -1 425 278 ;
|
||||
C 242 ; WX 220 ; N ograve ; B 43 -7 285 326 ;
|
||||
C 243 ; WX 220 ; N oacute ; B 43 -7 288 319 ;
|
||||
C 244 ; WX 220 ; N ocircumflex ; B 43 -7 359 319 ;
|
||||
C 245 ; WX 220 ; N otilde ; B 43 -7 296 278 ;
|
||||
C 246 ; WX 220 ; N odieresis ; B 43 -7 292 289 ;
|
||||
C 247 ; WX 359 ; N oe ; B 41 -7 426 193 ;
|
||||
C 248 ; WX 219 ; N oslash ; B 35 -24 288 204 ;
|
||||
C 249 ; WX 309 ; N ugrave ; B 40 -7 374 326 ;
|
||||
C 250 ; WX 310 ; N uacute ; B 41 -7 375 319 ;
|
||||
C 251 ; WX 309 ; N ucircumflex ; B 41 -7 406 319 ;
|
||||
C 252 ; WX 308 ; N udieresis ; B 40 -7 374 289 ;
|
||||
C 255 ; WX 689 ; N germandbls ; B 27 -106 656 502 ;
|
||||
EndCharMetrics
|
||||
EndFontMetrics
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,6 @@
|
||||
#Copyright ReportLab Europe Ltd. 2000-2017
|
||||
#see license.txt for license details
|
||||
#history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/__init__.py
|
||||
__version__='3.3.0'
|
||||
__doc__='''Framework for reusable object graphics, in PDF or bitmap form'''
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,152 @@
|
||||
#
|
||||
# Copyright (c) 1996-2000 Tyler C. Sarna <tsarna@sarna.org>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by Tyler C. Sarna.
|
||||
# 4. Neither the name of the author nor the names of contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
__all__ = tuple('''registerWidget getCodes getCodeNames createBarcodeDrawing createBarcodeImageInMemory'''.split())
|
||||
__version__ = '0.9'
|
||||
__doc__='''Popular barcodes available as reusable widgets'''
|
||||
|
||||
_widgets = []
|
||||
def registerWidget(widget):
|
||||
_widgets.append(widget)
|
||||
|
||||
def _reset():
|
||||
_widgets[:] = []
|
||||
from reportlab.graphics.barcode.widgets import BarcodeI2of5, BarcodeCode128, BarcodeStandard93,\
|
||||
BarcodeExtended93, BarcodeStandard39, BarcodeExtended39,\
|
||||
BarcodeMSI, BarcodeCodabar, BarcodeCode11, BarcodeFIM,\
|
||||
BarcodePOSTNET, BarcodeUSPS_4State, BarcodeCode128Auto, BarcodeECC200DataMatrix
|
||||
|
||||
#newer codes will typically get their own module
|
||||
from reportlab.graphics.barcode.eanbc import Ean13BarcodeWidget, Ean8BarcodeWidget, UPCA, Ean5BarcodeWidget, ISBNBarcodeWidget
|
||||
from reportlab.graphics.barcode.qr import QrCodeWidget
|
||||
for widget in (BarcodeI2of5,
|
||||
BarcodeCode128,
|
||||
BarcodeCode128Auto,
|
||||
BarcodeStandard93,
|
||||
BarcodeExtended93,
|
||||
BarcodeStandard39,
|
||||
BarcodeExtended39,
|
||||
BarcodeMSI,
|
||||
BarcodeCodabar,
|
||||
BarcodeCode11,
|
||||
BarcodeFIM,
|
||||
BarcodePOSTNET,
|
||||
BarcodeUSPS_4State,
|
||||
Ean13BarcodeWidget,
|
||||
Ean8BarcodeWidget,
|
||||
UPCA,
|
||||
Ean5BarcodeWidget,
|
||||
ISBNBarcodeWidget,
|
||||
QrCodeWidget,
|
||||
BarcodeECC200DataMatrix,
|
||||
):
|
||||
registerWidget(widget)
|
||||
from reportlab.graphics.barcode import dmtx
|
||||
if dmtx.pylibdmtx:
|
||||
registerWidget(dmtx.DataMatrixWidget)
|
||||
|
||||
_reset()
|
||||
from reportlab.rl_config import register_reset
|
||||
register_reset(_reset)
|
||||
|
||||
def getCodes():
|
||||
"""Returns a dict mapping code names to widgets"""
|
||||
#the module exports a dictionary of names to widgets, to make it easy for
|
||||
#apps and doc tools to display information about them.
|
||||
codes = {}
|
||||
for widget in _widgets:
|
||||
codeName = widget.codeName
|
||||
codes[codeName] = widget
|
||||
|
||||
return codes
|
||||
|
||||
def getCodeNames():
|
||||
"""Returns sorted list of supported bar code names"""
|
||||
return sorted(getCodes().keys())
|
||||
|
||||
def createBarcodeDrawing(codeName, **options):
|
||||
"""This creates and returns a drawing with a barcode.
|
||||
"""
|
||||
from reportlab.graphics.shapes import Drawing
|
||||
|
||||
codes = getCodes()
|
||||
bcc = codes[codeName]
|
||||
width = options.pop('width',None)
|
||||
height = options.pop('height',None)
|
||||
isoScale = options.pop('isoScale',0)
|
||||
kw = {}
|
||||
for k,v in options.items():
|
||||
if k.startswith('_') or k in bcc._attrMap: kw[k] = v
|
||||
bc = bcc(**kw)
|
||||
|
||||
|
||||
#Robin's new ones validate when setting the value property.
|
||||
#Ty Sarna's old ones do not. We need to test.
|
||||
if hasattr(bc, 'validate'):
|
||||
bc.validate() #raise exception if bad value
|
||||
if not bc.valid:
|
||||
raise ValueError("Illegal barcode with value '%s' in code '%s'" % (options.get('value',None), codeName))
|
||||
|
||||
#size it after setting the data
|
||||
x1, y1, x2, y2 = bc.getBounds()
|
||||
w = float(x2 - x1)
|
||||
h = float(y2 - y1)
|
||||
sx = width not in ('auto',None)
|
||||
sy = height not in ('auto',None)
|
||||
if sx or sy:
|
||||
sx = sx and width/w or 1.0
|
||||
sy = sy and height/h or 1.0
|
||||
if isoScale:
|
||||
if sx<1.0 and sy<1.0:
|
||||
sx = sy = max(sx,sy)
|
||||
else:
|
||||
sx = sy = min(sx,sy)
|
||||
|
||||
w *= sx
|
||||
h *= sy
|
||||
else:
|
||||
sx = sy = 1
|
||||
|
||||
#bc.x = -sx*x1
|
||||
#bc.y = -sy*y1
|
||||
d = Drawing(width=w,height=h,transform=[sx,0,0,sy,-sx*x1,-sy*y1])
|
||||
d.add(bc, "_bc")
|
||||
return d
|
||||
|
||||
def createBarcodeImageInMemory(codeName,**options):
|
||||
"""This creates and returns barcode as an image in memory.
|
||||
Takes same arguments as createBarcodeDrawing and also an
|
||||
optional format keyword which can be anything acceptable
|
||||
to Drawing.asString eg gif, pdf, tiff, py ......
|
||||
"""
|
||||
format = options.pop('format','png')
|
||||
d = createBarcodeDrawing(codeName, **options)
|
||||
return d.asString(format)
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,460 @@
|
||||
#
|
||||
# Copyright (c) 2000 Tyler C. Sarna <tsarna@sarna.org>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by Tyler C. Sarna.
|
||||
# 4. Neither the name of the author nor the names of contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
from reportlab.lib.units import inch
|
||||
from reportlab.lib.utils import asNative
|
||||
from reportlab.graphics.barcode.common import MultiWidthBarcode
|
||||
from string import digits
|
||||
|
||||
_patterns = {
|
||||
0 : 'BaBbBb', 1 : 'BbBaBb', 2 : 'BbBbBa',
|
||||
3 : 'AbAbBc', 4 : 'AbAcBb', 5 : 'AcAbBb',
|
||||
6 : 'AbBbAc', 7 : 'AbBcAb', 8 : 'AcBbAb',
|
||||
9 : 'BbAbAc', 10 : 'BbAcAb', 11 : 'BcAbAb',
|
||||
12 : 'AaBbCb', 13 : 'AbBaCb', 14 : 'AbBbCa',
|
||||
15 : 'AaCbBb', 16 : 'AbCaBb', 17 : 'AbCbBa',
|
||||
18 : 'BbCbAa', 19 : 'BbAaCb', 20 : 'BbAbCa',
|
||||
21 : 'BaCbAb', 22 : 'BbCaAb', 23 : 'CaBaCa',
|
||||
24 : 'CaAbBb', 25 : 'CbAaBb', 26 : 'CbAbBa',
|
||||
27 : 'CaBbAb', 28 : 'CbBaAb', 29 : 'CbBbAa',
|
||||
30 : 'BaBaBc', 31 : 'BaBcBa', 32 : 'BcBaBa',
|
||||
33 : 'AaAcBc', 34 : 'AcAaBc', 35 : 'AcAcBa',
|
||||
36 : 'AaBcAc', 37 : 'AcBaAc', 38 : 'AcBcAa',
|
||||
39 : 'BaAcAc', 40 : 'BcAaAc', 41 : 'BcAcAa',
|
||||
42 : 'AaBaCc', 43 : 'AaBcCa', 44 : 'AcBaCa',
|
||||
45 : 'AaCaBc', 46 : 'AaCcBa', 47 : 'AcCaBa',
|
||||
48 : 'CaCaBa', 49 : 'BaAcCa', 50 : 'BcAaCa',
|
||||
51 : 'BaCaAc', 52 : 'BaCcAa', 53 : 'BaCaCa',
|
||||
54 : 'CaAaBc', 55 : 'CaAcBa', 56 : 'CcAaBa',
|
||||
57 : 'CaBaAc', 58 : 'CaBcAa', 59 : 'CcBaAa',
|
||||
60 : 'CaDaAa', 61 : 'BbAdAa', 62 : 'DcAaAa',
|
||||
63 : 'AaAbBd', 64 : 'AaAdBb', 65 : 'AbAaBd',
|
||||
66 : 'AbAdBa', 67 : 'AdAaBb', 68 : 'AdAbBa',
|
||||
69 : 'AaBbAd', 70 : 'AaBdAb', 71 : 'AbBaAd',
|
||||
72 : 'AbBdAa', 73 : 'AdBaAb', 74 : 'AdBbAa',
|
||||
75 : 'BdAbAa', 76 : 'BbAaAd', 77 : 'DaCaAa',
|
||||
78 : 'BdAaAb', 79 : 'AcDaAa', 80 : 'AaAbDb',
|
||||
81 : 'AbAaDb', 82 : 'AbAbDa', 83 : 'AaDbAb',
|
||||
84 : 'AbDaAb', 85 : 'AbDbAa', 86 : 'DaAbAb',
|
||||
87 : 'DbAaAb', 88 : 'DbAbAa', 89 : 'BaBaDa',
|
||||
90 : 'BaDaBa', 91 : 'DaBaBa', 92 : 'AaAaDc',
|
||||
93 : 'AaAcDa', 94 : 'AcAaDa', 95 : 'AaDaAc',
|
||||
96 : 'AaDcAa', 97 : 'DaAaAc', 98 : 'DaAcAa',
|
||||
99 : 'AaCaDa', 100 : 'AaDaCa', 101 : 'CaAaDa',
|
||||
102 : 'DaAaCa', 103 : 'BaAdAb', 104 : 'BaAbAd',
|
||||
105 : 'BaAbCb', 106 : 'BcCaAaB'
|
||||
}
|
||||
|
||||
starta, startb, startc, stop = 103, 104, 105, 106
|
||||
|
||||
seta = {
|
||||
' ' : 0, '!' : 1, '"' : 2, '#' : 3,
|
||||
'$' : 4, '%' : 5, '&' : 6, '\'' : 7,
|
||||
'(' : 8, ')' : 9, '*' : 10, '+' : 11,
|
||||
',' : 12, '-' : 13, '.' : 14, '/' : 15,
|
||||
'0' : 16, '1' : 17, '2' : 18, '3' : 19,
|
||||
'4' : 20, '5' : 21, '6' : 22, '7' : 23,
|
||||
'8' : 24, '9' : 25, ':' : 26, ';' : 27,
|
||||
'<' : 28, '=' : 29, '>' : 30, '?' : 31,
|
||||
'@' : 32, 'A' : 33, 'B' : 34, 'C' : 35,
|
||||
'D' : 36, 'E' : 37, 'F' : 38, 'G' : 39,
|
||||
'H' : 40, 'I' : 41, 'J' : 42, 'K' : 43,
|
||||
'L' : 44, 'M' : 45, 'N' : 46, 'O' : 47,
|
||||
'P' : 48, 'Q' : 49, 'R' : 50, 'S' : 51,
|
||||
'T' : 52, 'U' : 53, 'V' : 54, 'W' : 55,
|
||||
'X' : 56, 'Y' : 57, 'Z' : 58, '[' : 59,
|
||||
'\\' : 60, ']' : 61, '^' : 62, '_' : 63,
|
||||
'\x00' : 64, '\x01' : 65, '\x02' : 66, '\x03' : 67,
|
||||
'\x04' : 68, '\x05' : 69, '\x06' : 70, '\x07' : 71,
|
||||
'\x08' : 72, '\x09' : 73, '\x0a' : 74, '\x0b' : 75,
|
||||
'\x0c' : 76, '\x0d' : 77, '\x0e' : 78, '\x0f' : 79,
|
||||
'\x10' : 80, '\x11' : 81, '\x12' : 82, '\x13' : 83,
|
||||
'\x14' : 84, '\x15' : 85, '\x16' : 86, '\x17' : 87,
|
||||
'\x18' : 88, '\x19' : 89, '\x1a' : 90, '\x1b' : 91,
|
||||
'\x1c' : 92, '\x1d' : 93, '\x1e' : 94, '\x1f' : 95,
|
||||
'\xf3' : 96, '\xf2' : 97, 'SHIFT' : 98, 'TO_C' : 99,
|
||||
'TO_B' : 100, '\xf4' : 101, '\xf1' : 102
|
||||
}
|
||||
|
||||
setb = {
|
||||
' ' : 0, '!' : 1, '"' : 2, '#' : 3,
|
||||
'$' : 4, '%' : 5, '&' : 6, '\'' : 7,
|
||||
'(' : 8, ')' : 9, '*' : 10, '+' : 11,
|
||||
',' : 12, '-' : 13, '.' : 14, '/' : 15,
|
||||
'0' : 16, '1' : 17, '2' : 18, '3' : 19,
|
||||
'4' : 20, '5' : 21, '6' : 22, '7' : 23,
|
||||
'8' : 24, '9' : 25, ':' : 26, ';' : 27,
|
||||
'<' : 28, '=' : 29, '>' : 30, '?' : 31,
|
||||
'@' : 32, 'A' : 33, 'B' : 34, 'C' : 35,
|
||||
'D' : 36, 'E' : 37, 'F' : 38, 'G' : 39,
|
||||
'H' : 40, 'I' : 41, 'J' : 42, 'K' : 43,
|
||||
'L' : 44, 'M' : 45, 'N' : 46, 'O' : 47,
|
||||
'P' : 48, 'Q' : 49, 'R' : 50, 'S' : 51,
|
||||
'T' : 52, 'U' : 53, 'V' : 54, 'W' : 55,
|
||||
'X' : 56, 'Y' : 57, 'Z' : 58, '[' : 59,
|
||||
'\\' : 60, ']' : 61, '^' : 62, '_' : 63,
|
||||
'`' : 64, 'a' : 65, 'b' : 66, 'c' : 67,
|
||||
'd' : 68, 'e' : 69, 'f' : 70, 'g' : 71,
|
||||
'h' : 72, 'i' : 73, 'j' : 74, 'k' : 75,
|
||||
'l' : 76, 'm' : 77, 'n' : 78, 'o' : 79,
|
||||
'p' : 80, 'q' : 81, 'r' : 82, 's' : 83,
|
||||
't' : 84, 'u' : 85, 'v' : 86, 'w' : 87,
|
||||
'x' : 88, 'y' : 89, 'z' : 90, '{' : 91,
|
||||
'|' : 92, '}' : 93, '~' : 94, '\x7f' : 95,
|
||||
'\xf3' : 96, '\xf2' : 97, 'SHIFT' : 98, 'TO_C' : 99,
|
||||
'\xf4' : 100, 'TO_A' : 101, '\xf1' : 102
|
||||
}
|
||||
|
||||
setc = {
|
||||
'00': 0, '01': 1, '02': 2, '03': 3, '04': 4,
|
||||
'05': 5, '06': 6, '07': 7, '08': 8, '09': 9,
|
||||
'10':10, '11':11, '12':12, '13':13, '14':14,
|
||||
'15':15, '16':16, '17':17, '18':18, '19':19,
|
||||
'20':20, '21':21, '22':22, '23':23, '24':24,
|
||||
'25':25, '26':26, '27':27, '28':28, '29':29,
|
||||
'30':30, '31':31, '32':32, '33':33, '34':34,
|
||||
'35':35, '36':36, '37':37, '38':38, '39':39,
|
||||
'40':40, '41':41, '42':42, '43':43, '44':44,
|
||||
'45':45, '46':46, '47':47, '48':48, '49':49,
|
||||
'50':50, '51':51, '52':52, '53':53, '54':54,
|
||||
'55':55, '56':56, '57':57, '58':58, '59':59,
|
||||
'60':60, '61':61, '62':62, '63':63, '64':64,
|
||||
'65':65, '66':66, '67':67, '68':68, '69':69,
|
||||
'70':70, '71':71, '72':72, '73':73, '74':74,
|
||||
'75':75, '76':76, '77':77, '78':78, '79':79,
|
||||
'80':80, '81':81, '82':82, '83':83, '84':84,
|
||||
'85':85, '86':86, '87':87, '88':88, '89':89,
|
||||
'90':90, '91':91, '92':92, '93':93, '94':94,
|
||||
'95':95, '96':96, '97':97, '98':98, '99':99,
|
||||
|
||||
'TO_B' : 100, 'TO_A' : 101, '\xf1' : 102
|
||||
}
|
||||
|
||||
setmap = {
|
||||
'TO_A' : (seta, setb),
|
||||
'TO_B' : (setb, seta),
|
||||
'TO_C' : (setc, None),
|
||||
'START_A' : (starta, seta, setb),
|
||||
'START_B' : (startb, setb, seta),
|
||||
'START_C' : (startc, setc, None),
|
||||
}
|
||||
cStarts = ('START_B','TO_A','TO_B')
|
||||
tos = list(setmap.keys())
|
||||
|
||||
class Code128(MultiWidthBarcode):
|
||||
"""
|
||||
Code 128 is a very compact symbology that can encode the entire
|
||||
128 character ASCII set, plus 4 special control codes,
|
||||
(FNC1-FNC4, expressed in the input string as \xf1 to \xf4).
|
||||
Code 128 can also encode digits at double density (2 per byte)
|
||||
and has a mandatory checksum. Code 128 is well supported and
|
||||
commonly used -- for example, by UPS for tracking labels.
|
||||
|
||||
Because of these qualities, Code 128 is probably the best choice
|
||||
for a linear symbology today (assuming you have a choice).
|
||||
|
||||
Options that may be passed to constructor:
|
||||
|
||||
value (int, or numeric string. required.):
|
||||
The value to encode.
|
||||
|
||||
barWidth (float, default .0075):
|
||||
X-Dimension, or width of the smallest element
|
||||
Minumum is .0075 inch (7.5 mils).
|
||||
|
||||
barHeight (float, see default below):
|
||||
Height of the symbol. Default is the height of the two
|
||||
bearer bars (if they exist) plus the greater of .25 inch
|
||||
or .15 times the symbol's length.
|
||||
|
||||
quiet (bool, default 1):
|
||||
Wether to include quiet zones in the symbol.
|
||||
|
||||
lquiet (float, see default below):
|
||||
Quiet zone size to left of code, if quiet is true.
|
||||
Default is the greater of .25 inch, or 10 barWidth
|
||||
|
||||
rquiet (float, defaults as above):
|
||||
Quiet zone size to right left of code, if quiet is true.
|
||||
|
||||
Sources of Information on Code 128:
|
||||
|
||||
http://www.semiconductor.agilent.com/barcode/sg/Misc/code_128.html
|
||||
http://www.adams1.com/pub/russadam/128code.html
|
||||
http://www.barcodeman.com/c128.html
|
||||
|
||||
Official Spec, "ANSI/AIM BC4-1999, ISS" is available for US$45 from
|
||||
http://www.aimglobal.org/aimstore/
|
||||
"""
|
||||
barWidth = inch * 0.0075
|
||||
lquiet = None
|
||||
rquiet = None
|
||||
quiet = 1
|
||||
barHeight = None
|
||||
def __init__(self, value='', **args):
|
||||
value = str(value) if isinstance(value,int) else asNative(value)
|
||||
|
||||
for k, v in args.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
if self.quiet:
|
||||
if self.lquiet is None:
|
||||
self.lquiet = max(inch * 0.25, self.barWidth * 10.0)
|
||||
if self.rquiet is None:
|
||||
self.rquiet = max(inch * 0.25, self.barWidth * 10.0)
|
||||
else:
|
||||
self.lquiet = self.rquiet = 0.0
|
||||
|
||||
MultiWidthBarcode.__init__(self, value)
|
||||
|
||||
def validate(self):
|
||||
vval = ""
|
||||
self.valid = 1
|
||||
for c in self.value:
|
||||
if ord(c) > 127 and c not in '\xf1\xf2\xf3\xf4':
|
||||
self.valid = 0
|
||||
continue
|
||||
vval = vval + c
|
||||
self.validated = vval
|
||||
return vval
|
||||
|
||||
|
||||
def _try_TO_C(self, l):
|
||||
'''Improved version of old _trailingDigitsToC(self, l) inspired by'''
|
||||
i = 0
|
||||
nl = []
|
||||
while i < len(l):
|
||||
startpos = i
|
||||
rl = []
|
||||
savings = -1 # the TO_C costs one character
|
||||
while i < len(l):
|
||||
if l[i] in cStarts:
|
||||
j = i
|
||||
break
|
||||
elif l[i] == '\xf1':
|
||||
rl.append(l[i])
|
||||
i += 1
|
||||
continue
|
||||
elif l[i] in digits \
|
||||
and l[i+1] in digits:
|
||||
rl.append(l[i] + l[i+1])
|
||||
i += 2
|
||||
savings += 1
|
||||
continue
|
||||
else:
|
||||
if l[i] in digits and l[i+1]=='STOP':
|
||||
rrl = []
|
||||
rsavings = -1 #we need a TO_C
|
||||
k = i
|
||||
while k>startpos:
|
||||
if l[k]=='\xf1':
|
||||
rrl.append(l[i])
|
||||
k -= 1
|
||||
elif l[k] in digits and l[k-1] in digits:
|
||||
rrl.append(l[k-1]+l[k])
|
||||
rsavings += 1
|
||||
k -= 2
|
||||
else:
|
||||
break
|
||||
rrl.reverse()
|
||||
if rsavings>savings+int(savings>=0 and (startpos and nl[-1] in cStarts))-1:
|
||||
nl += l[startpos]
|
||||
startpos += 1
|
||||
rl = rrl
|
||||
del rrl
|
||||
i += 1
|
||||
break
|
||||
ta = not (l[i]=='STOP' or j==i)
|
||||
xs = savings>=0 and (startpos and nl[-1] in cStarts)
|
||||
if savings+int(xs) > int(ta):
|
||||
if xs:
|
||||
toc = nl[-1][:-1]+'C'
|
||||
del nl[-1]
|
||||
else:
|
||||
toc = 'TO_C'
|
||||
nl += [toc]+rl
|
||||
if ta:
|
||||
nl.append('TO'+l[j][-2:])
|
||||
nl.append(l[i])
|
||||
else:
|
||||
nl += l[startpos:i+1]
|
||||
i += 1
|
||||
return nl
|
||||
|
||||
def encode(self):
|
||||
# First, encode using only B
|
||||
s = self.validated
|
||||
l = ['START_B']
|
||||
for c in s:
|
||||
if c not in setb:
|
||||
l = l + ['TO_A', c, 'TO_B']
|
||||
else:
|
||||
l.append(c)
|
||||
l.append('STOP')
|
||||
|
||||
l = self._try_TO_C(l)
|
||||
|
||||
# Finally, replace START_X,TO_Y with START_Y
|
||||
if l[1] in tos:
|
||||
l[:2] = ['START_' + l[1][-1]]
|
||||
|
||||
# print repr(l)
|
||||
|
||||
# encode into numbers
|
||||
start, set, shset = setmap[l[0]]
|
||||
e = [start]
|
||||
|
||||
l = l[1:-1]
|
||||
while l:
|
||||
c = l[0]
|
||||
if c == 'SHIFT':
|
||||
e = e + [set[c], shset[l[1]]]
|
||||
l = l[2:]
|
||||
elif c in tos:
|
||||
e.append(set[c])
|
||||
set, shset = setmap[c]
|
||||
l = l[1:]
|
||||
else:
|
||||
e.append(set[c])
|
||||
l = l[1:]
|
||||
|
||||
c = e[0]
|
||||
for i in range(1, len(e)):
|
||||
c = c + i * e[i]
|
||||
self.encoded = e + [c % 103, stop]
|
||||
return self.encoded
|
||||
|
||||
def decompose(self):
|
||||
self.decomposed = ''.join([_patterns[c] for c in self.encoded])
|
||||
return self.decomposed
|
||||
|
||||
def _humanText(self):
|
||||
return self.value
|
||||
|
||||
class Code128Auto(Code128):
|
||||
'''contributed by https://bitbucket.org/kylemacfarlane/
|
||||
see https://bitbucket.org/rptlab/reportlab/issues/69/implementations-of-code-128-auto-and-data
|
||||
'''
|
||||
def encode(self):
|
||||
s = self.validated
|
||||
|
||||
current_set = None
|
||||
l = []
|
||||
value = list(s)
|
||||
while value:
|
||||
c = value.pop(0)
|
||||
if c in digits and value and value[0] in digits:
|
||||
c += value.pop(0)
|
||||
|
||||
if c in setc:
|
||||
set_ = 'C'
|
||||
elif c in setb:
|
||||
set_ = 'B'
|
||||
else:
|
||||
set_ = 'A'
|
||||
|
||||
if current_set != set_:
|
||||
if current_set:
|
||||
l.append('TO_' + set_)
|
||||
else:
|
||||
l.append('START_' + set_)
|
||||
current_set = set_
|
||||
|
||||
l.append(c)
|
||||
l.append('STOP')
|
||||
|
||||
start, set, shset = setmap[l[0]]
|
||||
e = [start]
|
||||
|
||||
l = l[1:-1]
|
||||
while l:
|
||||
c = l[0]
|
||||
if c == 'SHIFT':
|
||||
e = e + [set[c], shset[l[1]]]
|
||||
l = l[2:]
|
||||
elif c in tos:
|
||||
e.append(set[c])
|
||||
set, shset = setmap[c]
|
||||
l = l[1:]
|
||||
else:
|
||||
e.append(set[c])
|
||||
l = l[1:]
|
||||
|
||||
c = e[0]
|
||||
for i in range(1, len(e)):
|
||||
c = c + i * e[i]
|
||||
self.encoded = e + [c % 103, stop]
|
||||
return self.encoded
|
||||
|
||||
if __name__=='__main__':
|
||||
def main():
|
||||
from reportlab.graphics.barcode.code128 import Code128
|
||||
from reportlab.platypus import Spacer, SimpleDocTemplate
|
||||
from reportlab.lib.units import inch
|
||||
from reportlab.lib.styles import getSampleStyleSheet
|
||||
from reportlab.platypus.paragraph import Paragraph
|
||||
from reportlab.platypus.flowables import KeepTogether
|
||||
styles = getSampleStyleSheet()
|
||||
styleN = styles['Normal']
|
||||
styleH = styles['Heading1']
|
||||
story = []
|
||||
storyAdd = story.append
|
||||
for s in (
|
||||
'BBBB123456BBB',
|
||||
'BBBB12345BBB',
|
||||
'BBBB1234BBB',
|
||||
'BBBB123BBB',
|
||||
'BBBB12BBB',
|
||||
'BBBB1BBB',
|
||||
'BBBB123456aa',
|
||||
'BBBB1234aa',
|
||||
'BBBB123aa',
|
||||
'BBBB12aa',
|
||||
'BBBB1aa',
|
||||
'BBBB123456',
|
||||
'BBBB12345',
|
||||
'BBBB1234',
|
||||
'BBBB123',
|
||||
'BBBB12',
|
||||
'BBBB1',
|
||||
'\xf11234B',
|
||||
'Ba\xf11234B',
|
||||
'Ba12',
|
||||
'Ba123B',
|
||||
'Ba1234B',
|
||||
'BBBB1234567',
|
||||
'BBBB1234567aa',
|
||||
):
|
||||
storyAdd(KeepTogether([Paragraph('Code 128 %r' % s, styleN),Code128(s)]))
|
||||
storyAdd(Spacer(inch,inch))
|
||||
SimpleDocTemplate('code128-out.pdf').build(story)
|
||||
main()
|
||||
@@ -0,0 +1,244 @@
|
||||
#
|
||||
# Copyright (c) 1996-2000 Tyler C. Sarna <tsarna@sarna.org>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by Tyler C. Sarna.
|
||||
# 4. Neither the name of the author nor the names of contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
from reportlab.lib.units import inch
|
||||
from reportlab.lib.utils import asNative
|
||||
from reportlab.graphics.barcode.common import Barcode
|
||||
from string import ascii_uppercase, ascii_lowercase, digits as string_digits
|
||||
|
||||
_patterns = {
|
||||
'0': ("bsbSBsBsb", 0), '1': ("BsbSbsbsB", 1),
|
||||
'2': ("bsBSbsbsB", 2), '3': ("BsBSbsbsb", 3),
|
||||
'4': ("bsbSBsbsB", 4), '5': ("BsbSBsbsb", 5),
|
||||
'6': ("bsBSBsbsb", 6), '7': ("bsbSbsBsB", 7),
|
||||
'8': ("BsbSbsBsb", 8), '9': ("bsBSbsBsb", 9),
|
||||
'A': ("BsbsbSbsB", 10), 'B': ("bsBsbSbsB", 11),
|
||||
'C': ("BsBsbSbsb", 12), 'D': ("bsbsBSbsB", 13),
|
||||
'E': ("BsbsBSbsb", 14), 'F': ("bsBsBSbsb", 15),
|
||||
'G': ("bsbsbSBsB", 16), 'H': ("BsbsbSBsb", 17),
|
||||
'I': ("bsBsbSBsb", 18), 'J': ("bsbsBSBsb", 19),
|
||||
'K': ("BsbsbsbSB", 20), 'L': ("bsBsbsbSB", 21),
|
||||
'M': ("BsBsbsbSb", 22), 'N': ("bsbsBsbSB", 23),
|
||||
'O': ("BsbsBsbSb", 24), 'P': ("bsBsBsbSb", 25),
|
||||
'Q': ("bsbsbsBSB", 26), 'R': ("BsbsbsBSb", 27),
|
||||
'S': ("bsBsbsBSb", 28), 'T': ("bsbsBsBSb", 29),
|
||||
'U': ("BSbsbsbsB", 30), 'V': ("bSBsbsbsB", 31),
|
||||
'W': ("BSBsbsbsb", 32), 'X': ("bSbsBsbsB", 33),
|
||||
'Y': ("BSbsBsbsb", 34), 'Z': ("bSBsBsbsb", 35),
|
||||
'-': ("bSbsbsBsB", 36), '.': ("BSbsbsBsb", 37),
|
||||
' ': ("bSBsbsBsb", 38), '*': ("bSbsBsBsb", None),
|
||||
'$': ("bSbSbSbsb", 39), '/': ("bSbSbsbSb", 40),
|
||||
'+': ("bSbsbSbSb", 41), '%': ("bsbSbSbSb", 42)
|
||||
}
|
||||
|
||||
_stdchrs = string_digits + ascii_uppercase + "-. $/+%"
|
||||
|
||||
_extended = {
|
||||
'\0': "%U", '\01': "$A", '\02': "$B", '\03': "$C",
|
||||
'\04': "$D", '\05': "$E", '\06': "$F", '\07': "$G",
|
||||
'\010': "$H", '\011': "$I", '\012': "$J", '\013': "$K",
|
||||
'\014': "$L", '\015': "$M", '\016': "$N", '\017': "$O",
|
||||
'\020': "$P", '\021': "$Q", '\022': "$R", '\023': "$S",
|
||||
'\024': "$T", '\025': "$U", '\026': "$V", '\027': "$W",
|
||||
'\030': "$X", '\031': "$Y", '\032': "$Z", '\033': "%A",
|
||||
'\034': "%B", '\035': "%C", '\036': "%D", '\037': "%E",
|
||||
'!': "/A", '"': "/B", '#': "/C", '$': "/D",
|
||||
'%': "/E", '&': "/F", '\'': "/G", '(': "/H",
|
||||
')': "/I", '*': "/J", '+': "/K", ',': "/L",
|
||||
'/': "/O", ':': "/Z", ';': "%F", '<': "%G",
|
||||
'=': "%H", '>': "%I", '?': "%J", '@': "%V",
|
||||
'[': "%K", '\\': "%L", ']': "%M", '^': "%N",
|
||||
'_': "%O", '`': "%W", 'a': "+A", 'b': "+B",
|
||||
'c': "+C", 'd': "+D", 'e': "+E", 'f': "+F",
|
||||
'g': "+G", 'h': "+H", 'i': "+I", 'j': "+J",
|
||||
'k': "+K", 'l': "+L", 'm': "+M", 'n': "+N",
|
||||
'o': "+O", 'p': "+P", 'q': "+Q", 'r': "+R",
|
||||
's': "+S", 't': "+T", 'u': "+U", 'v': "+V",
|
||||
'w': "+W", 'x': "+X", 'y': "+Y", 'z': "+Z",
|
||||
'{': "%P", '|': "%Q", '}': "%R", '~': "%S",
|
||||
'\177': "%T"
|
||||
}
|
||||
|
||||
|
||||
_extchrs = _stdchrs + ascii_lowercase + \
|
||||
"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017" + \
|
||||
"\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" + \
|
||||
"*!'#&\"(),:;<=>?@[\\]^_`{|}~\177"
|
||||
|
||||
def _encode39(value, cksum, stop):
|
||||
v = sum([_patterns[c][1] for c in value]) % 43
|
||||
if cksum:
|
||||
value += _stdchrs[v]
|
||||
if stop: value = '*'+value+'*'
|
||||
return value
|
||||
|
||||
class _Code39Base(Barcode):
|
||||
barWidth = inch * 0.0075
|
||||
lquiet = None
|
||||
rquiet = None
|
||||
quiet = 1
|
||||
gap = None
|
||||
barHeight = None
|
||||
ratio = 2.2
|
||||
checksum = 1
|
||||
bearers = 0.0
|
||||
stop = 1
|
||||
def __init__(self, value = "", **args):
|
||||
value = asNative(value)
|
||||
for k, v in args.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
if self.quiet:
|
||||
if self.lquiet is None:
|
||||
self.lquiet = max(inch * 0.25, self.barWidth * 10.0)
|
||||
self.rquiet = max(inch * 0.25, self.barWidth * 10.0)
|
||||
else:
|
||||
self.lquiet = self.rquiet = 0.0
|
||||
|
||||
Barcode.__init__(self, value)
|
||||
|
||||
def decompose(self):
|
||||
dval = ""
|
||||
for c in self.encoded:
|
||||
dval = dval + _patterns[c][0] + 'i'
|
||||
self.decomposed = dval[:-1]
|
||||
return self.decomposed
|
||||
|
||||
def _humanText(self):
|
||||
return self.stop and self.encoded[1:-1] or self.encoded
|
||||
|
||||
class Standard39(_Code39Base):
|
||||
"""
|
||||
Options that may be passed to constructor:
|
||||
|
||||
value (int, or numeric string required.):
|
||||
The value to encode.
|
||||
|
||||
barWidth (float, default .0075):
|
||||
X-Dimension, or width of the smallest element
|
||||
Minumum is .0075 inch (7.5 mils).
|
||||
|
||||
ratio (float, default 2.2):
|
||||
The ratio of wide elements to narrow elements.
|
||||
Must be between 2.0 and 3.0 (or 2.2 and 3.0 if the
|
||||
barWidth is greater than 20 mils (.02 inch))
|
||||
|
||||
gap (float or None, default None):
|
||||
width of intercharacter gap. None means "use barWidth".
|
||||
|
||||
barHeight (float, see default below):
|
||||
Height of the symbol. Default is the height of the two
|
||||
bearer bars (if they exist) plus the greater of .25 inch
|
||||
or .15 times the symbol's length.
|
||||
|
||||
checksum (bool, default 1):
|
||||
Wether to compute and include the check digit
|
||||
|
||||
bearers (float, in units of barWidth. default 0):
|
||||
Height of bearer bars (horizontal bars along the top and
|
||||
bottom of the barcode). Default is 0 (no bearers).
|
||||
|
||||
quiet (bool, default 1):
|
||||
Wether to include quiet zones in the symbol.
|
||||
|
||||
lquiet (float, see default below):
|
||||
Quiet zone size to left of code, if quiet is true.
|
||||
Default is the greater of .25 inch, or .15 times the symbol's
|
||||
length.
|
||||
|
||||
rquiet (float, defaults as above):
|
||||
Quiet zone size to right left of code, if quiet is true.
|
||||
|
||||
stop (bool, default 1):
|
||||
Whether to include start/stop symbols.
|
||||
|
||||
Sources of Information on Code 39:
|
||||
|
||||
http://www.semiconductor.agilent.com/barcode/sg/Misc/code_39.html
|
||||
http://www.adams1.com/pub/russadam/39code.html
|
||||
http://www.barcodeman.com/c39_1.html
|
||||
|
||||
Official Spec, "ANSI/AIM BC1-1995, USS" is available for US$45 from
|
||||
http://www.aimglobal.org/aimstore/
|
||||
"""
|
||||
def validate(self):
|
||||
vval = [].append
|
||||
self.valid = 1
|
||||
for c in self.value:
|
||||
if c in ascii_lowercase:
|
||||
c = c.upper()
|
||||
if c not in _stdchrs:
|
||||
self.valid = 0
|
||||
continue
|
||||
vval(c)
|
||||
self.validated = ''.join(vval.__self__)
|
||||
return self.validated
|
||||
|
||||
def encode(self):
|
||||
self.encoded = _encode39(self.validated, self.checksum, self.stop)
|
||||
return self.encoded
|
||||
|
||||
class Extended39(_Code39Base):
|
||||
"""
|
||||
Extended Code 39 is a convention for encoding additional characters
|
||||
not present in stanmdard Code 39 by using pairs of characters to
|
||||
represent the characters missing in Standard Code 39.
|
||||
|
||||
See Standard39 for arguments.
|
||||
|
||||
Sources of Information on Extended Code 39:
|
||||
|
||||
http://www.semiconductor.agilent.com/barcode/sg/Misc/xcode_39.html
|
||||
http://www.barcodeman.com/c39_ext.html
|
||||
"""
|
||||
def validate(self):
|
||||
vval = ""
|
||||
self.valid = 1
|
||||
for c in self.value:
|
||||
if c not in _extchrs:
|
||||
self.valid = 0
|
||||
continue
|
||||
vval = vval + c
|
||||
self.validated = vval
|
||||
return vval
|
||||
|
||||
def encode(self):
|
||||
self.encoded = ""
|
||||
for c in self.validated:
|
||||
if c in _extended:
|
||||
self.encoded = self.encoded + _extended[c]
|
||||
elif c in _stdchrs:
|
||||
self.encoded = self.encoded + c
|
||||
else:
|
||||
raise ValueError
|
||||
self.encoded = _encode39(self.encoded, self.checksum,self.stop)
|
||||
return self.encoded
|
||||
@@ -0,0 +1,234 @@
|
||||
#
|
||||
# Copyright (c) 2000 Tyler C. Sarna <tsarna@sarna.org>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by Tyler C. Sarna.
|
||||
# 4. Neither the name of the author nor the names of contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
from reportlab.lib.units import inch
|
||||
from reportlab.lib.utils import asNative
|
||||
from reportlab.graphics.barcode.common import MultiWidthBarcode
|
||||
|
||||
_patterns = {
|
||||
'0' : ('AcAaAb', 0), '1' : ('AaAbAc', 1), '2' : ('AaAcAb', 2),
|
||||
'3' : ('AaAdAa', 3), '4' : ('AbAaAc', 4), '5' : ('AbAbAb', 5),
|
||||
'6' : ('AbAcAa', 6), '7' : ('AaAaAd', 7), '8' : ('AcAbAa', 8),
|
||||
'9' : ('AdAaAa', 9), 'A' : ('BaAaAc', 10), 'B' : ('BaAbAb', 11),
|
||||
'C' : ('BaAcAa', 12), 'D' : ('BbAaAb', 13), 'E' : ('BbAbAa', 14),
|
||||
'F' : ('BcAaAa', 15), 'G' : ('AaBaAc', 16), 'H' : ('AaBbAb', 17),
|
||||
'I' : ('AaBcAa', 18), 'J' : ('AbBaAb', 19), 'K' : ('AcBaAa', 20),
|
||||
'L' : ('AaAaBc', 21), 'M' : ('AaAbBb', 22), 'N' : ('AaAcBa', 23),
|
||||
'O' : ('AbAaBb', 24), 'P' : ('AcAaBa', 25), 'Q' : ('BaBaAb', 26),
|
||||
'R' : ('BaBbAa', 27), 'S' : ('BaAaBb', 28), 'T' : ('BaAbBa', 29),
|
||||
'U' : ('BbAaBa', 30), 'V' : ('BbBaAa', 31), 'W' : ('AaBaBb', 32),
|
||||
'X' : ('AaBbBa', 33), 'Y' : ('AbBaBa', 34), 'Z' : ('AbCaAa', 35),
|
||||
'-' : ('AbAaCa', 36), '.' : ('CaAaAb', 37), ' ' : ('CaAbAa', 38),
|
||||
'$' : ('CbAaAa', 39), '/' : ('AaBaCa', 40), '+' : ('AaCaBa', 41),
|
||||
'%' : ('BaAaCa', 42), '#' : ('AbAbBa', 43), '!' : ('CaBaAa', 44),
|
||||
'=' : ('CaAaBa', 45), '&' : ('AbBbAa', 46),
|
||||
'start' : ('AaAaDa', -1), 'stop' : ('AaAaDaA', -2)
|
||||
}
|
||||
|
||||
_charsbyval = {}
|
||||
for k, v in _patterns.items():
|
||||
_charsbyval[v[1]] = k
|
||||
|
||||
_extended = {
|
||||
'\x00' : '!U', '\x01' : '#A', '\x02' : '#B', '\x03' : '#C',
|
||||
'\x04' : '#D', '\x05' : '#E', '\x06' : '#F', '\x07' : '#G',
|
||||
'\x08' : '#H', '\x09' : '#I', '\x0a' : '#J', '\x0b' : '#K',
|
||||
'\x0c' : '#L', '\x0d' : '#M', '\x0e' : '#N', '\x0f' : '#O',
|
||||
'\x10' : '#P', '\x11' : '#Q', '\x12' : '#R', '\x13' : '#S',
|
||||
'\x14' : '#T', '\x15' : '#U', '\x16' : '#V', '\x17' : '#W',
|
||||
'\x18' : '#X', '\x19' : '#Y', '\x1a' : '#Z', '\x1b' : '!A',
|
||||
'\x1c' : '!B', '\x1d' : '!C', '\x1e' : '!D', '\x1f' : '!E',
|
||||
'!' : '=A', '"' : '=B', '#' : '=C', '$' : '=D',
|
||||
'%' : '=E', '&' : '=F', '\'' : '=G', '(' : '=H',
|
||||
')' : '=I', '*' : '=J', '+' : '=K', ',' : '=L',
|
||||
'/' : '=O', ':' : '=Z', ';' : '!F', '<' : '!G',
|
||||
'=' : '!H', '>' : '!I', '?' : '!J', '@' : '!V',
|
||||
'[' : '!K', '\\' : '!L', ']' : '!M', '^' : '!N',
|
||||
'_' : '!O', '`' : '!W', 'a' : '&A', 'b' : '&B',
|
||||
'c' : '&C', 'd' : '&D', 'e' : '&E', 'f' : '&F',
|
||||
'g' : '&G', 'h' : '&H', 'i' : '&I', 'j' : '&J',
|
||||
'k' : '&K', 'l' : '&L', 'm' : '&M', 'n' : '&N',
|
||||
'o' : '&O', 'p' : '&P', 'q' : '&Q', 'r' : '&R',
|
||||
's' : '&S', 't' : '&T', 'u' : '&U', 'v' : '&V',
|
||||
'w' : '&W', 'x' : '&X', 'y' : '&Y', 'z' : '&Z',
|
||||
'{' : '!P', '|' : '!Q', '}' : '!R', '~' : '!S',
|
||||
'\x7f' : '!T'
|
||||
}
|
||||
|
||||
def _encode93(str):
|
||||
s = list(str)
|
||||
s.reverse()
|
||||
|
||||
# compute 'C' checksum
|
||||
i = 0; v = 1; c = 0
|
||||
while i < len(s):
|
||||
c = c + v * _patterns[s[i]][1]
|
||||
i = i + 1; v = v + 1
|
||||
if v > 20:
|
||||
v = 1
|
||||
s.insert(0, _charsbyval[c % 47])
|
||||
|
||||
# compute 'K' checksum
|
||||
i = 0; v = 1; c = 0
|
||||
while i < len(s):
|
||||
c = c + v * _patterns[s[i]][1]
|
||||
i = i + 1; v = v + 1
|
||||
if v > 15:
|
||||
v = 1
|
||||
s.insert(0, _charsbyval[c % 47])
|
||||
|
||||
s.reverse()
|
||||
|
||||
return ''.join(s)
|
||||
|
||||
class _Code93Base(MultiWidthBarcode):
|
||||
barWidth = inch * 0.0075
|
||||
lquiet = None
|
||||
rquiet = None
|
||||
quiet = 1
|
||||
barHeight = None
|
||||
stop = 1
|
||||
def __init__(self, value='', **args):
|
||||
|
||||
if type(value) is type(1):
|
||||
value = asNative(value)
|
||||
|
||||
for (k, v) in args.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
if self.quiet:
|
||||
if self.lquiet is None:
|
||||
self.lquiet = max(inch * 0.25, self.barWidth * 10.0)
|
||||
self.rquiet = max(inch * 0.25, self.barWidth * 10.0)
|
||||
else:
|
||||
self.lquiet = self.rquiet = 0.0
|
||||
|
||||
MultiWidthBarcode.__init__(self, value)
|
||||
|
||||
def decompose(self):
|
||||
dval = self.stop and [_patterns['start'][0]] or []
|
||||
dval += [_patterns[c][0] for c in self.encoded]
|
||||
if self.stop: dval.append(_patterns['stop'][0])
|
||||
self.decomposed = ''.join(dval)
|
||||
return self.decomposed
|
||||
|
||||
class Standard93(_Code93Base):
|
||||
"""
|
||||
Code 93 is a Uppercase alphanumeric symbology with some punctuation.
|
||||
See Extended Code 93 for a variant that can represent the entire
|
||||
128 characrter ASCII set.
|
||||
|
||||
Options that may be passed to constructor:
|
||||
|
||||
value (int, or numeric string. required.):
|
||||
The value to encode.
|
||||
|
||||
barWidth (float, default .0075):
|
||||
X-Dimension, or width of the smallest element
|
||||
Minumum is .0075 inch (7.5 mils).
|
||||
|
||||
barHeight (float, see default below):
|
||||
Height of the symbol. Default is the height of the two
|
||||
bearer bars (if they exist) plus the greater of .25 inch
|
||||
or .15 times the symbol's length.
|
||||
|
||||
quiet (bool, default 1):
|
||||
Wether to include quiet zones in the symbol.
|
||||
|
||||
lquiet (float, see default below):
|
||||
Quiet zone size to left of code, if quiet is true.
|
||||
Default is the greater of .25 inch, or 10 barWidth
|
||||
|
||||
rquiet (float, defaults as above):
|
||||
Quiet zone size to right left of code, if quiet is true.
|
||||
|
||||
stop (bool, default 1):
|
||||
Whether to include start/stop symbols.
|
||||
|
||||
Sources of Information on Code 93:
|
||||
|
||||
http://www.semiconductor.agilent.com/barcode/sg/Misc/code_93.html
|
||||
|
||||
Official Spec, "NSI/AIM BC5-1995, USS" is available for US$45 from
|
||||
http://www.aimglobal.org/aimstore/
|
||||
"""
|
||||
def validate(self):
|
||||
vval = ""
|
||||
self.valid = 1
|
||||
for c in self.value.upper():
|
||||
if c not in _patterns:
|
||||
self.valid = 0
|
||||
continue
|
||||
vval = vval + c
|
||||
self.validated = vval
|
||||
return vval
|
||||
|
||||
def encode(self):
|
||||
self.encoded = _encode93(self.validated)
|
||||
return self.encoded
|
||||
|
||||
|
||||
class Extended93(_Code93Base):
|
||||
"""
|
||||
Extended Code 93 is a convention for encoding the entire 128 character
|
||||
set using pairs of characters to represent the characters missing in
|
||||
Standard Code 93. It is very much like Extended Code 39 in that way.
|
||||
|
||||
See Standard93 for arguments.
|
||||
"""
|
||||
|
||||
def validate(self):
|
||||
vval = []
|
||||
self.valid = 1
|
||||
a = vval.append
|
||||
for c in self.value:
|
||||
if c not in _patterns and c not in _extended:
|
||||
self.valid = 0
|
||||
continue
|
||||
a(c)
|
||||
self.validated = ''.join(vval)
|
||||
return self.validated
|
||||
|
||||
def encode(self):
|
||||
self.encoded = ""
|
||||
for c in self.validated:
|
||||
if c in _patterns:
|
||||
self.encoded = self.encoded + c
|
||||
elif c in _extended:
|
||||
self.encoded = self.encoded + _extended[c]
|
||||
else:
|
||||
raise ValueError
|
||||
self.encoded = _encode93(self.encoded)
|
||||
return self.encoded
|
||||
|
||||
def _humanText(self):
|
||||
return self.validated+self.encoded[-2:]
|
||||
@@ -0,0 +1,775 @@
|
||||
#
|
||||
# Copyright (c) 1996-2000 Tyler C. Sarna <tsarna@sarna.org>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by Tyler C. Sarna.
|
||||
# 4. Neither the name of the author nor the names of contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
from reportlab.platypus.flowables import Flowable
|
||||
from reportlab.lib.units import inch
|
||||
from string import ascii_lowercase, ascii_uppercase, digits as string_digits
|
||||
|
||||
class Barcode(Flowable):
|
||||
"""Abstract Base for barcodes. Includes implementations of
|
||||
some methods suitable for the more primitive barcode types"""
|
||||
|
||||
fontName = 'Courier'
|
||||
fontSize = 12
|
||||
humanReadable = 0
|
||||
|
||||
def _humanText(self):
|
||||
return self.encoded
|
||||
|
||||
def __init__(self, value='',**kwd):
|
||||
self.value = str(value)
|
||||
|
||||
self._setKeywords(**kwd)
|
||||
if not hasattr(self, 'gap'):
|
||||
self.gap = None
|
||||
|
||||
|
||||
def _calculate(self):
|
||||
self.validate()
|
||||
self.encode()
|
||||
self.decompose()
|
||||
self.computeSize()
|
||||
|
||||
def _setKeywords(self,**kwd):
|
||||
for (k, v) in kwd.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
def validate(self):
|
||||
self.valid = 1
|
||||
self.validated = self.value
|
||||
|
||||
def encode(self):
|
||||
self.encoded = self.validated
|
||||
|
||||
def decompose(self):
|
||||
self.decomposed = self.encoded
|
||||
|
||||
def computeSize(self, *args):
|
||||
barWidth = self.barWidth
|
||||
wx = barWidth * self.ratio
|
||||
|
||||
if self.gap == None:
|
||||
self.gap = barWidth
|
||||
|
||||
w = 0.0
|
||||
|
||||
for c in self.decomposed:
|
||||
if c in 'sb':
|
||||
w = w + barWidth
|
||||
elif c in 'SB':
|
||||
w = w + wx
|
||||
else: # 'i'
|
||||
w = w + self.gap
|
||||
|
||||
if self.barHeight is None:
|
||||
self.barHeight = w * 0.15
|
||||
self.barHeight = max(0.25 * inch, self.barHeight)
|
||||
if self.bearers:
|
||||
self.barHeight = self.barHeight + self.bearers * 2.0 * barWidth
|
||||
|
||||
if self.quiet:
|
||||
w += self.lquiet + self.rquiet
|
||||
|
||||
|
||||
self._height = self.barHeight
|
||||
self._width = w
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
self._calculate()
|
||||
return self._width
|
||||
@width.setter
|
||||
def width(self,v):
|
||||
pass
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
self._calculate()
|
||||
return self._height
|
||||
@height.setter
|
||||
def height(self,v):
|
||||
pass
|
||||
|
||||
def draw(self):
|
||||
self._calculate()
|
||||
barWidth = self.barWidth
|
||||
wx = barWidth * self.ratio
|
||||
|
||||
left = self.quiet and self.lquiet or 0
|
||||
b = self.bearers * barWidth
|
||||
bb = b * 0.5
|
||||
tb = self.barHeight - (b * 1.5)
|
||||
|
||||
for c in self.decomposed:
|
||||
if c == 'i':
|
||||
left = left + self.gap
|
||||
elif c == 's':
|
||||
left = left + barWidth
|
||||
elif c == 'S':
|
||||
left = left + wx
|
||||
elif c == 'b':
|
||||
self.rect(left, bb, barWidth, tb)
|
||||
left = left + barWidth
|
||||
elif c == 'B':
|
||||
self.rect(left, bb, wx, tb)
|
||||
left = left + wx
|
||||
|
||||
if self.bearers:
|
||||
if getattr(self,'bearerBox', None):
|
||||
canv = self.canv
|
||||
if hasattr(canv,'_Gadd'):
|
||||
#this is a widget rect takes other arguments
|
||||
canv.rect(bb, bb, self.width, self.barHeight-b,
|
||||
strokeWidth=b, strokeColor=self.barFillColor or self.barStrokeColor, fillColor=None)
|
||||
else:
|
||||
canv.saveState()
|
||||
canv.setLineWidth(b)
|
||||
canv.rect(bb, bb, self.width, self.barHeight-b, stroke=1, fill=0)
|
||||
canv.restoreState()
|
||||
else:
|
||||
w = self._width - (self.lquiet + self.rquiet)
|
||||
self.rect(self.lquiet, 0, w, b)
|
||||
self.rect(self.lquiet, self.barHeight - b, w, b)
|
||||
|
||||
self.drawHumanReadable()
|
||||
|
||||
def drawHumanReadable(self):
|
||||
if self.humanReadable:
|
||||
#we have text
|
||||
from reportlab.pdfbase.pdfmetrics import getAscent, stringWidth
|
||||
s = str(self._humanText())
|
||||
fontSize = self.fontSize
|
||||
fontName = self.fontName
|
||||
w = stringWidth(s,fontName,fontSize)
|
||||
width = self._width
|
||||
if self.quiet:
|
||||
width -= self.lquiet+self.rquiet
|
||||
x = self.lquiet
|
||||
else:
|
||||
x = 0
|
||||
if w>width: fontSize *= width/float(w)
|
||||
y = 1.07*getAscent(fontName)*fontSize/1000.
|
||||
self.annotate(x+width/2.,-y,s,fontName,fontSize)
|
||||
|
||||
def rect(self, x, y, w, h):
|
||||
self.canv.rect(x, y, w, h, stroke=0, fill=1)
|
||||
|
||||
def annotate(self,x,y,text,fontName,fontSize,anchor='middle'):
|
||||
canv = self.canv
|
||||
canv.saveState()
|
||||
canv.setFont(self.fontName,fontSize)
|
||||
if anchor=='middle': func = 'drawCentredString'
|
||||
elif anchor=='end': func = 'drawRightString'
|
||||
else: func = 'drawString'
|
||||
getattr(canv,func)(x,y,text)
|
||||
canv.restoreState()
|
||||
|
||||
def _checkVal(self, name, v, allowed):
|
||||
if v not in allowed:
|
||||
raise ValueError('%s attribute %s is invalid %r\nnot in allowed %r' % (
|
||||
self.__class__.__name__, name, v, allowed))
|
||||
return v
|
||||
|
||||
class MultiWidthBarcode(Barcode):
|
||||
"""Base for variable-bar-width codes like Code93 and Code128"""
|
||||
|
||||
def computeSize(self, *args):
|
||||
barWidth = self.barWidth
|
||||
oa, oA = ord('a') - 1, ord('A') - 1
|
||||
|
||||
w = 0.0
|
||||
|
||||
for c in self.decomposed:
|
||||
oc = ord(c)
|
||||
if c in ascii_lowercase:
|
||||
w = w + barWidth * (oc - oa)
|
||||
elif c in ascii_uppercase:
|
||||
w = w + barWidth * (oc - oA)
|
||||
|
||||
if self.barHeight is None:
|
||||
self.barHeight = w * 0.15
|
||||
self.barHeight = max(0.25 * inch, self.barHeight)
|
||||
|
||||
if self.quiet:
|
||||
w += self.lquiet + self.rquiet
|
||||
|
||||
self._height = self.barHeight
|
||||
self._width = w
|
||||
|
||||
def draw(self):
|
||||
self._calculate()
|
||||
oa, oA = ord('a') - 1, ord('A') - 1
|
||||
barWidth = self.barWidth
|
||||
left = self.quiet and self.lquiet or 0
|
||||
|
||||
for c in self.decomposed:
|
||||
oc = ord(c)
|
||||
if c in ascii_lowercase:
|
||||
left = left + (oc - oa) * barWidth
|
||||
elif c in ascii_uppercase:
|
||||
w = (oc - oA) * barWidth
|
||||
self.rect(left, 0, w, self.barHeight)
|
||||
left += w
|
||||
self.drawHumanReadable()
|
||||
|
||||
class I2of5(Barcode):
|
||||
"""
|
||||
Interleaved 2 of 5 is a numeric-only barcode. It encodes an even
|
||||
number of digits; if an odd number is given, a 0 is prepended.
|
||||
|
||||
Options that may be passed to constructor:
|
||||
|
||||
value (int, or numeric string required.):
|
||||
The value to encode.
|
||||
|
||||
barWidth (float, default .0075):
|
||||
X-Dimension, or width of the smallest element
|
||||
Minumum is .0075 inch (7.5 mils).
|
||||
|
||||
ratio (float, default 2.2):
|
||||
The ratio of wide elements to narrow elements.
|
||||
Must be between 2.0 and 3.0 (or 2.2 and 3.0 if the
|
||||
barWidth is greater than 20 mils (.02 inch))
|
||||
|
||||
gap (float or None, default None):
|
||||
width of intercharacter gap. None means "use barWidth".
|
||||
|
||||
barHeight (float, see default below):
|
||||
Height of the symbol. Default is the height of the two
|
||||
bearer bars (if they exist) plus the greater of .25 inch
|
||||
or .15 times the symbol's length.
|
||||
|
||||
checksum (bool, default 1):
|
||||
Whether to compute and include the check digit
|
||||
|
||||
bearers (float, in units of barWidth. default 3.0):
|
||||
Height of bearer bars (horizontal bars along the top and
|
||||
bottom of the barcode). Default is 3 x-dimensions.
|
||||
Set to zero for no bearer bars. (Bearer bars help detect
|
||||
misscans, so it is suggested to leave them on).
|
||||
|
||||
bearerBox (bool default False)
|
||||
if true draw a true rectangle of width bearers around the barcode.
|
||||
|
||||
quiet (bool, default 1):
|
||||
Whether to include quiet zones in the symbol.
|
||||
|
||||
lquiet (float, see default below):
|
||||
Quiet zone size to left of code, if quiet is true.
|
||||
Default is the greater of .25 inch, or .15 times the symbol's
|
||||
length.
|
||||
|
||||
rquiet (float, defaults as above):
|
||||
Quiet zone size to right left of code, if quiet is true.
|
||||
|
||||
stop (bool, default 1):
|
||||
Whether to include start/stop symbols.
|
||||
|
||||
Sources of Information on Interleaved 2 of 5:
|
||||
|
||||
http://www.semiconductor.agilent.com/barcode/sg/Misc/i_25.html
|
||||
http://www.adams1.com/pub/russadam/i25code.html
|
||||
|
||||
Official Spec, "ANSI/AIM BC2-1995, USS" is available for US$45 from
|
||||
http://www.aimglobal.org/aimstore/
|
||||
"""
|
||||
|
||||
patterns = {
|
||||
'start' : 'bsbs',
|
||||
'stop' : 'Bsb',
|
||||
|
||||
'B0' : 'bbBBb', 'S0' : 'ssSSs',
|
||||
'B1' : 'BbbbB', 'S1' : 'SsssS',
|
||||
'B2' : 'bBbbB', 'S2' : 'sSssS',
|
||||
'B3' : 'BBbbb', 'S3' : 'SSsss',
|
||||
'B4' : 'bbBbB', 'S4' : 'ssSsS',
|
||||
'B5' : 'BbBbb', 'S5' : 'SsSss',
|
||||
'B6' : 'bBBbb', 'S6' : 'sSSss',
|
||||
'B7' : 'bbbBB', 'S7' : 'sssSS',
|
||||
'B8' : 'BbbBb', 'S8' : 'SssSs',
|
||||
'B9' : 'bBbBb', 'S9' : 'sSsSs'
|
||||
}
|
||||
|
||||
barHeight = None
|
||||
barWidth = inch * 0.0075
|
||||
ratio = 2.2
|
||||
checksum = 1
|
||||
bearers = 3.0
|
||||
bearerBox = False
|
||||
quiet = 1
|
||||
lquiet = None
|
||||
rquiet = None
|
||||
stop = 1
|
||||
|
||||
def __init__(self, value='', **args):
|
||||
|
||||
if type(value) == type(1):
|
||||
value = str(value)
|
||||
|
||||
for k, v in args.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
if self.quiet:
|
||||
if self.lquiet is None:
|
||||
self.lquiet = min(inch * 0.25, self.barWidth * 10.0)
|
||||
self.rquiet = min(inch * 0.25, self.barWidth * 10.0)
|
||||
else:
|
||||
self.lquiet = self.rquiet = 0.0
|
||||
|
||||
Barcode.__init__(self, value)
|
||||
|
||||
def validate(self):
|
||||
vval = ""
|
||||
self.valid = 1
|
||||
for c in self.value.strip():
|
||||
if c not in string_digits:
|
||||
self.valid = 0
|
||||
continue
|
||||
vval = vval + c
|
||||
self.validated = vval
|
||||
return vval
|
||||
|
||||
def encode(self):
|
||||
s = self.validated
|
||||
cs = self.checksum
|
||||
c = len(s)
|
||||
|
||||
#ensure len(result)%2 == 0, checksum included
|
||||
if ((c % 2 == 0) and cs) or ((c % 2 == 1) and not cs):
|
||||
s = '0' + s
|
||||
c += 1
|
||||
|
||||
if cs:
|
||||
c = 3*sum([int(s[i]) for i in range(0,c,2)])+sum([int(s[i]) for i in range(1,c,2)])
|
||||
s += str((10 - c) % 10)
|
||||
|
||||
self.encoded = s
|
||||
|
||||
def decompose(self):
|
||||
dval = self.stop and [self.patterns['start']] or []
|
||||
a = dval.append
|
||||
|
||||
for i in range(0, len(self.encoded), 2):
|
||||
b = self.patterns['B' + self.encoded[i]]
|
||||
s = self.patterns['S' + self.encoded[i+1]]
|
||||
|
||||
for i in range(0, len(b)):
|
||||
a(b[i] + s[i])
|
||||
|
||||
if self.stop: a(self.patterns['stop'])
|
||||
self.decomposed = ''.join(dval)
|
||||
return self.decomposed
|
||||
|
||||
class MSI(Barcode):
|
||||
"""
|
||||
MSI is a numeric-only barcode.
|
||||
|
||||
Options that may be passed to constructor:
|
||||
|
||||
value (int, or numeric string required.):
|
||||
The value to encode.
|
||||
|
||||
barWidth (float, default .0075):
|
||||
X-Dimension, or width of the smallest element
|
||||
|
||||
ratio (float, default 2.2):
|
||||
The ratio of wide elements to narrow elements.
|
||||
|
||||
gap (float or None, default None):
|
||||
width of intercharacter gap. None means "use barWidth".
|
||||
|
||||
barHeight (float, see default below):
|
||||
Height of the symbol. Default is the height of the two
|
||||
bearer bars (if they exist) plus the greater of .25 inch
|
||||
or .15 times the symbol's length.
|
||||
|
||||
checksum (bool, default 1):
|
||||
Wether to compute and include the check digit
|
||||
|
||||
bearers (float, in units of barWidth. default 0):
|
||||
Height of bearer bars (horizontal bars along the top and
|
||||
bottom of the barcode). Default is 0 (no bearers).
|
||||
|
||||
lquiet (float, see default below):
|
||||
Quiet zone size to left of code, if quiet is true.
|
||||
Default is the greater of .25 inch, or 10 barWidths.
|
||||
|
||||
rquiet (float, defaults as above):
|
||||
Quiet zone size to right left of code, if quiet is true.
|
||||
|
||||
stop (bool, default 1):
|
||||
Whether to include start/stop symbols.
|
||||
|
||||
Sources of Information on MSI Bar Code:
|
||||
|
||||
http://www.semiconductor.agilent.com/barcode/sg/Misc/msi_code.html
|
||||
http://www.adams1.com/pub/russadam/plessy.html
|
||||
"""
|
||||
|
||||
patterns = {
|
||||
'start' : 'Bs', 'stop' : 'bSb',
|
||||
|
||||
'0' : 'bSbSbSbS', '1' : 'bSbSbSBs',
|
||||
'2' : 'bSbSBsbS', '3' : 'bSbSBsBs',
|
||||
'4' : 'bSBsbSbS', '5' : 'bSBsbSBs',
|
||||
'6' : 'bSBsBsbS', '7' : 'bSBsBsBs',
|
||||
'8' : 'BsbSbSbS', '9' : 'BsbSbSBs'
|
||||
}
|
||||
|
||||
stop = 1
|
||||
barHeight = None
|
||||
barWidth = inch * 0.0075
|
||||
ratio = 2.2
|
||||
checksum = 1
|
||||
bearers = 0.0
|
||||
quiet = 1
|
||||
lquiet = None
|
||||
rquiet = None
|
||||
|
||||
def __init__(self, value="", **args):
|
||||
|
||||
if type(value) == type(1):
|
||||
value = str(value)
|
||||
|
||||
for k, v in args.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
if self.quiet:
|
||||
if self.lquiet is None:
|
||||
self.lquiet = max(inch * 0.25, self.barWidth * 10.0)
|
||||
self.rquiet = max(inch * 0.25, self.barWidth * 10.0)
|
||||
else:
|
||||
self.lquiet = self.rquiet = 0.0
|
||||
|
||||
Barcode.__init__(self, value)
|
||||
|
||||
def validate(self):
|
||||
vval = ""
|
||||
self.valid = 1
|
||||
for c in self.value.strip():
|
||||
if c not in string_digits:
|
||||
self.valid = 0
|
||||
continue
|
||||
vval = vval + c
|
||||
self.validated = vval
|
||||
return vval
|
||||
|
||||
def encode(self):
|
||||
s = self.validated
|
||||
|
||||
if self.checksum:
|
||||
c = ''
|
||||
for i in range(1, len(s), 2):
|
||||
c = c + s[i]
|
||||
d = str(int(c) * 2)
|
||||
t = 0
|
||||
for c in d:
|
||||
t = t + int(c)
|
||||
for i in range(0, len(s), 2):
|
||||
t = t + int(s[i])
|
||||
c = 10 - (t % 10)
|
||||
|
||||
s = s + str(c)
|
||||
|
||||
self.encoded = s
|
||||
|
||||
def decompose(self):
|
||||
dval = self.stop and [self.patterns['start']] or []
|
||||
dval += [self.patterns[c] for c in self.encoded]
|
||||
if self.stop: dval.append(self.patterns['stop'])
|
||||
self.decomposed = ''.join(dval)
|
||||
return self.decomposed
|
||||
|
||||
class Codabar(Barcode):
|
||||
"""
|
||||
Codabar is a numeric plus some puntuation ("-$:/.+") barcode
|
||||
with four start/stop characters (A, B, C, and D).
|
||||
|
||||
Options that may be passed to constructor:
|
||||
|
||||
value (string required.):
|
||||
The value to encode.
|
||||
|
||||
barWidth (float, default .0065):
|
||||
X-Dimension, or width of the smallest element
|
||||
minimum is 6.5 mils (.0065 inch)
|
||||
|
||||
ratio (float, default 2.0):
|
||||
The ratio of wide elements to narrow elements.
|
||||
|
||||
gap (float or None, default None):
|
||||
width of intercharacter gap. None means "use barWidth".
|
||||
|
||||
barHeight (float, see default below):
|
||||
Height of the symbol. Default is the height of the two
|
||||
bearer bars (if they exist) plus the greater of .25 inch
|
||||
or .15 times the symbol's length.
|
||||
|
||||
checksum (bool, default 0):
|
||||
Whether to compute and include the check digit
|
||||
|
||||
bearers (float, in units of barWidth. default 0):
|
||||
Height of bearer bars (horizontal bars along the top and
|
||||
bottom of the barcode). Default is 0 (no bearers).
|
||||
|
||||
quiet (bool, default 1):
|
||||
Whether to include quiet zones in the symbol.
|
||||
|
||||
stop (bool, default 1):
|
||||
Whether to include start/stop symbols.
|
||||
|
||||
lquiet (float, see default below):
|
||||
Quiet zone size to left of code, if quiet is true.
|
||||
Default is the greater of .25 inch, or 10 barWidth
|
||||
|
||||
rquiet (float, defaults as above):
|
||||
Quiet zone size to right left of code, if quiet is true.
|
||||
|
||||
Sources of Information on Codabar
|
||||
|
||||
http://www.semiconductor.agilent.com/barcode/sg/Misc/codabar.html
|
||||
http://www.barcodeman.com/codabar.html
|
||||
|
||||
Official Spec, "ANSI/AIM BC3-1995, USS" is available for US$45 from
|
||||
http://www.aimglobal.org/aimstore/
|
||||
"""
|
||||
|
||||
patterns = {
|
||||
'0': 'bsbsbSB', '1': 'bsbsBSb', '2': 'bsbSbsB',
|
||||
'3': 'BSbsbsb', '4': 'bsBsbSb', '5': 'BsbsbSb',
|
||||
'6': 'bSbsbsB', '7': 'bSbsBsb', '8': 'bSBsbsb',
|
||||
'9': 'BsbSbsb', '-': 'bsbSBsb', '$': 'bsBSbsb',
|
||||
':': 'BsbsBsB', '/': 'BsBsbsB', '.': 'BsBsBsb',
|
||||
'+': 'bsBsBsB', 'A': 'bsBSbSb', 'B': 'bSbSbsB',
|
||||
'C': 'bsbSbSB', 'D': 'bsbSBSb'
|
||||
}
|
||||
|
||||
values = {
|
||||
'0' : 0, '1' : 1, '2' : 2, '3' : 3, '4' : 4,
|
||||
'5' : 5, '6' : 6, '7' : 7, '8' : 8, '9' : 9,
|
||||
'-' : 10, '$' : 11, ':' : 12, '/' : 13, '.' : 14,
|
||||
'+' : 15, 'A' : 16, 'B' : 17, 'C' : 18, 'D' : 19
|
||||
}
|
||||
|
||||
chars = string_digits + "-$:/.+"
|
||||
|
||||
stop = 1
|
||||
barHeight = None
|
||||
barWidth = inch * 0.0065
|
||||
ratio = 2.0 # XXX ?
|
||||
checksum = 0
|
||||
bearers = 0.0
|
||||
quiet = 1
|
||||
lquiet = None
|
||||
rquiet = None
|
||||
|
||||
def __init__(self, value='', **args):
|
||||
if type(value) == type(1):
|
||||
value = str(value)
|
||||
|
||||
for k, v in args.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
if self.quiet:
|
||||
if self.lquiet is None:
|
||||
self.lquiet = min(inch * 0.25, self.barWidth * 10.0)
|
||||
self.rquiet = min(inch * 0.25, self.barWidth * 10.0)
|
||||
else:
|
||||
self.lquiet = self.rquiet = 0.0
|
||||
|
||||
Barcode.__init__(self, value)
|
||||
|
||||
def validate(self):
|
||||
vval = ""
|
||||
self.valid = 1
|
||||
s = self.value.strip()
|
||||
for i in range(0, len(s)):
|
||||
c = s[i]
|
||||
if c not in self.chars:
|
||||
if ((i != 0) and (i != len(s) - 1)) or (c not in 'ABCD'):
|
||||
self.Valid = 0
|
||||
continue
|
||||
vval = vval + c
|
||||
|
||||
if self.stop:
|
||||
if vval[0] not in 'ABCD':
|
||||
vval = 'A' + vval
|
||||
if vval[-1] not in 'ABCD':
|
||||
vval = vval + vval[0]
|
||||
|
||||
self.validated = vval
|
||||
return vval
|
||||
|
||||
def encode(self):
|
||||
s = self.validated
|
||||
|
||||
if self.checksum:
|
||||
v = sum([self.values[c] for c in s])
|
||||
s += self.chars[v % 16]
|
||||
|
||||
self.encoded = s
|
||||
|
||||
def decompose(self):
|
||||
dval = ''.join([self.patterns[c]+'i' for c in self.encoded])
|
||||
self.decomposed = dval[:-1]
|
||||
return self.decomposed
|
||||
|
||||
class Code11(Barcode):
|
||||
"""
|
||||
Code 11 is an almost-numeric barcode. It encodes the digits 0-9 plus
|
||||
dash ("-"). 11 characters total, hence the name.
|
||||
|
||||
value (int or string required.):
|
||||
The value to encode.
|
||||
|
||||
barWidth (float, default .0075):
|
||||
X-Dimension, or width of the smallest element
|
||||
|
||||
ratio (float, default 2.2):
|
||||
The ratio of wide elements to narrow elements.
|
||||
|
||||
gap (float or None, default None):
|
||||
width of intercharacter gap. None means "use barWidth".
|
||||
|
||||
barHeight (float, see default below):
|
||||
Height of the symbol. Default is the height of the two
|
||||
bearer bars (if they exist) plus the greater of .25 inch
|
||||
or .15 times the symbol's length.
|
||||
|
||||
checksum (0 none, 1 1-digit, 2 2-digit, -1 auto, default -1):
|
||||
How many checksum digits to include. -1 ("auto") means
|
||||
1 if the number of digits is 10 or less, else 2.
|
||||
|
||||
bearers (float, in units of barWidth. default 0):
|
||||
Height of bearer bars (horizontal bars along the top and
|
||||
bottom of the barcode). Default is 0 (no bearers).
|
||||
|
||||
quiet (bool, default 1):
|
||||
Wether to include quiet zones in the symbol.
|
||||
|
||||
lquiet (float, see default below):
|
||||
Quiet zone size to left of code, if quiet is true.
|
||||
Default is the greater of .25 inch, or 10 barWidth
|
||||
|
||||
rquiet (float, defaults as above):
|
||||
Quiet zone size to right left of code, if quiet is true.
|
||||
|
||||
Sources of Information on Code 11:
|
||||
|
||||
http://www.cwi.nl/people/dik/english/codes/barcodes.html
|
||||
"""
|
||||
|
||||
chars = '0123456789-'
|
||||
|
||||
patterns = {
|
||||
'0' : 'bsbsB', '1' : 'BsbsB', '2' : 'bSbsB',
|
||||
'3' : 'BSbsb', '4' : 'bsBsB', '5' : 'BsBsb',
|
||||
'6' : 'bSBsb', '7' : 'bsbSB', '8' : 'BsbSb',
|
||||
'9' : 'Bsbsb', '-' : 'bsBsb', 'S' : 'bsBSb' # Start/Stop
|
||||
}
|
||||
|
||||
values = {
|
||||
'0' : 0, '1' : 1, '2' : 2, '3' : 3, '4' : 4,
|
||||
'5' : 5, '6' : 6, '7' : 7, '8' : 8, '9' : 9,
|
||||
'-' : 10,
|
||||
}
|
||||
|
||||
stop = 1
|
||||
barHeight = None
|
||||
barWidth = inch * 0.0075
|
||||
ratio = 2.2 # XXX ?
|
||||
checksum = -1 # Auto
|
||||
bearers = 0.0
|
||||
quiet = 1
|
||||
lquiet = None
|
||||
rquiet = None
|
||||
def __init__(self, value='', **args):
|
||||
if type(value) == type(1):
|
||||
value = str(value)
|
||||
|
||||
for k, v in args.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
if self.quiet:
|
||||
if self.lquiet is None:
|
||||
self.lquiet = min(inch * 0.25, self.barWidth * 10.0)
|
||||
self.rquiet = min(inch * 0.25, self.barWidth * 10.0)
|
||||
else:
|
||||
self.lquiet = self.rquiet = 0.0
|
||||
|
||||
Barcode.__init__(self, value)
|
||||
|
||||
def validate(self):
|
||||
vval = ""
|
||||
self.valid = 1
|
||||
s = self.value.strip()
|
||||
for i in range(0, len(s)):
|
||||
c = s[i]
|
||||
if c not in self.chars:
|
||||
self.Valid = 0
|
||||
continue
|
||||
vval = vval + c
|
||||
|
||||
self.validated = vval
|
||||
return vval
|
||||
|
||||
def _addCSD(self,s,m):
|
||||
# compute first checksum
|
||||
i = c = 0
|
||||
v = 1
|
||||
V = self.values
|
||||
while i < len(s):
|
||||
c += v * V[s[-(i+1)]]
|
||||
i += 1
|
||||
v += 1
|
||||
if v==m:
|
||||
v = 1
|
||||
return s+self.chars[c % 11]
|
||||
|
||||
def encode(self):
|
||||
s = self.validated
|
||||
|
||||
tcs = self.checksum
|
||||
if tcs<0:
|
||||
self.checksum = tcs = 1+int(len(s)>10)
|
||||
|
||||
if tcs > 0: s = self._addCSD(s,11)
|
||||
if tcs > 1: s = self._addCSD(s,10)
|
||||
|
||||
self.encoded = self.stop and ('S' + s + 'S') or s
|
||||
|
||||
def decompose(self):
|
||||
self.decomposed = ''.join([(self.patterns[c]+'i') for c in self.encoded])[:-1]
|
||||
return self.decomposed
|
||||
|
||||
def _humanText(self):
|
||||
return self.stop and self.encoded[1:-1] or self.encoded
|
||||
@@ -0,0 +1,273 @@
|
||||
try:
|
||||
from pylibdmtx import pylibdmtx
|
||||
except ImportError:
|
||||
pylibdmtx = None
|
||||
__all__ = ()
|
||||
else:
|
||||
__all__=('DataMatrix',)
|
||||
|
||||
from reportlab.graphics.barcode.common import Barcode
|
||||
from reportlab.lib.utils import asBytes
|
||||
from reportlab.platypus.paraparser import _num as paraparser_num
|
||||
from reportlab.graphics.widgetbase import Widget
|
||||
from reportlab.lib.validators import isColor, isString, isColorOrNone, isNumber, isBoxAnchor
|
||||
from reportlab.lib.attrmap import AttrMap, AttrMapValue
|
||||
from reportlab.lib.colors import toColor
|
||||
from reportlab.graphics.shapes import Group, Rect
|
||||
|
||||
def _numConv(x):
|
||||
return x if isinstance(x,(int,float)) else paraparser_num(x)
|
||||
|
||||
class _DMTXCheck:
|
||||
@classmethod
|
||||
def pylibdmtx_check(cls):
|
||||
if not pylibdmtx:
|
||||
raise ValueError('The %s class requires package pylibdmtx' % cls.__name__)
|
||||
|
||||
class DataMatrix(Barcode,_DMTXCheck):
|
||||
def __init__(self, value='', **kwds):
|
||||
self.pylibdmtx_check()
|
||||
self._recalc = True
|
||||
self.value = value
|
||||
self.cellSize = kwds.pop('cellSize','5x5')
|
||||
self.size = kwds.pop('size','SquareAuto')
|
||||
self.encoding = kwds.pop('encoding','Ascii')
|
||||
self.anchor = kwds.pop('anchor','sw')
|
||||
self.color = kwds.pop('color',(0,0,0))
|
||||
self.bgColor = kwds.pop('bgColor',None)
|
||||
self.x = kwds.pop('x',0)
|
||||
self.y = kwds.pop('y',0)
|
||||
self.border = kwds.pop('border',5)
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self._value
|
||||
|
||||
@value.setter
|
||||
def value(self,v):
|
||||
self._value = asBytes(v)
|
||||
self._recalc = True
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
return self._size
|
||||
|
||||
@size.setter
|
||||
def size(self,v):
|
||||
self._size = self._checkVal('size', v, pylibdmtx.ENCODING_SIZE_NAMES)
|
||||
self._recalc = True
|
||||
|
||||
@property
|
||||
def border(self):
|
||||
return self._border
|
||||
|
||||
@border.setter
|
||||
def border(self,v):
|
||||
self._border = _numConv(v)
|
||||
self._recalc = True
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
return self._x
|
||||
|
||||
@x.setter
|
||||
def x(self,v):
|
||||
self._x = _numConv(v)
|
||||
self._recalc = True
|
||||
|
||||
@property
|
||||
def y(self):
|
||||
return self._y
|
||||
|
||||
@y.setter
|
||||
def y(self,v):
|
||||
self._y = _numConv(v)
|
||||
self._recalc = True
|
||||
|
||||
@property
|
||||
def cellSize(self):
|
||||
return self._cellSize
|
||||
|
||||
@size.setter
|
||||
def cellSize(self,v):
|
||||
self._cellSize = v
|
||||
self._recalc = True
|
||||
|
||||
@property
|
||||
def encoding(self):
|
||||
return self._encoding
|
||||
|
||||
@encoding.setter
|
||||
def encoding(self,v):
|
||||
self._encoding = self._checkVal('encoding', v, pylibdmtx.ENCODING_SCHEME_NAMES)
|
||||
self._recalc = True
|
||||
|
||||
@property
|
||||
def anchor(self):
|
||||
return self._anchor
|
||||
|
||||
@anchor.setter
|
||||
def anchor(self,v):
|
||||
self._anchor = self._checkVal('anchor', v, ('n','ne','e','se','s','sw','w','nw','c'))
|
||||
self._recalc = True
|
||||
|
||||
def recalc(self):
|
||||
if not self._recalc: return
|
||||
data = self._value
|
||||
size = self._size
|
||||
encoding = self._encoding
|
||||
e = pylibdmtx.encode(data, size=size, scheme=encoding)
|
||||
iW = e.width
|
||||
iH = e.height
|
||||
p = e.pixels
|
||||
iCellSize = 5
|
||||
bpp = 3 #bytes per pixel
|
||||
rowLen = iW*bpp
|
||||
cellLen = iCellSize*bpp
|
||||
assert len(p)//rowLen == iH
|
||||
matrix = list(filter(None,
|
||||
(''.join(
|
||||
(('x' if p[j:j+bpp] != b'\xff\xff\xff' else ' ')
|
||||
for j in range(i,i+rowLen,cellLen))).strip()
|
||||
for i in range(0,iH*rowLen,rowLen*iCellSize))))
|
||||
self._nRows = len(matrix)
|
||||
self._nCols = len(matrix[-1])
|
||||
self._matrix = '\n'.join(matrix)
|
||||
|
||||
cellWidth = self._cellSize
|
||||
if cellWidth:
|
||||
cellWidth = cellWidth.split('x')
|
||||
if len(cellWidth)>2:
|
||||
raise ValueError('cellSize needs to be distance x distance not %r' % self._cellSize)
|
||||
elif len(cellWidth)==2:
|
||||
cellWidth, cellHeight = cellWidth
|
||||
else:
|
||||
cellWidth = cellHeight = cellWidth[0]
|
||||
cellWidth = _numConv(cellWidth)
|
||||
cellHeight = _numConv(cellHeight)
|
||||
else:
|
||||
cellWidth = cellHeight = iCellSize
|
||||
self._cellWidth = cellWidth
|
||||
self._cellHeight = cellHeight
|
||||
self._recalc = False
|
||||
self._bord = max(self.border,cellWidth,cellHeight)
|
||||
self._width = cellWidth*self._nCols + 2*self._bord
|
||||
self._height = cellHeight*self._nRows + 2*self._bord
|
||||
|
||||
@property
|
||||
def matrix(self):
|
||||
self.recalc()
|
||||
return self._matrix
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
self.recalc()
|
||||
return self._width
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
self.recalc()
|
||||
return self._height
|
||||
|
||||
@property
|
||||
def cellWidth(self):
|
||||
self.recalc()
|
||||
return self._cellWidth
|
||||
|
||||
@property
|
||||
def cellHeight(self):
|
||||
self.recalc()
|
||||
return self._cellHeight
|
||||
|
||||
def draw(self):
|
||||
self.recalc()
|
||||
canv = self.canv
|
||||
w = self.width
|
||||
h = self.height
|
||||
x = self.x
|
||||
y = self.y
|
||||
b = self._bord
|
||||
|
||||
anchor = self.anchor
|
||||
if anchor in ('nw','n','ne'):
|
||||
y -= h
|
||||
elif anchor in ('c','e','w'):
|
||||
y -= h//2
|
||||
if anchor in ('ne','e','se'):
|
||||
x -= w
|
||||
elif anchor in ('n','c','s'):
|
||||
x -= w//2
|
||||
|
||||
canv.saveState()
|
||||
if self.bgColor:
|
||||
canv.setFillColor(toColor(self.bgColor))
|
||||
canv.rect(x, y-h, w, h, fill=1, stroke=0)
|
||||
canv.setFillColor(toColor(self.color))
|
||||
canv.setStrokeColor(None)
|
||||
|
||||
cellWidth = self.cellWidth
|
||||
cellHeight = self.cellHeight
|
||||
yr = y - b - cellHeight
|
||||
x += b
|
||||
for row in self.matrix.split('\n'):
|
||||
xr = x
|
||||
for c in row:
|
||||
if c=='x':
|
||||
canv.rect(xr, yr, cellWidth, cellHeight, fill=1, stroke=0)
|
||||
xr += cellWidth
|
||||
yr -= cellHeight
|
||||
canv.restoreState()
|
||||
|
||||
|
||||
class DataMatrixWidget(Widget,_DMTXCheck):
|
||||
codeName = "DataMatrix"
|
||||
_attrMap = AttrMap(
|
||||
BASE = Widget,
|
||||
value = AttrMapValue(isString, desc='Datamatrix data'),
|
||||
x = AttrMapValue(isNumber, desc='x-coord'),
|
||||
y = AttrMapValue(isNumber, desc='y-coord'),
|
||||
color = AttrMapValue(isColor, desc='foreground color'),
|
||||
bgColor = AttrMapValue(isColorOrNone, desc='background color'),
|
||||
encoding = AttrMapValue(isString, desc='encoding'),
|
||||
size = AttrMapValue(isString, desc='size'),
|
||||
cellSize = AttrMapValue(isString, desc='cellSize'),
|
||||
anchor = AttrMapValue(isBoxAnchor, desc='anchor pooint for x,y'),
|
||||
)
|
||||
|
||||
_defaults = dict(
|
||||
x = ('0',_numConv),
|
||||
y = ('0',_numConv),
|
||||
color = ('black',toColor),
|
||||
bgColor = (None,lambda _: toColor(_) if _ is not None else _),
|
||||
encoding = ('Ascii',None),
|
||||
size = ('SquareAuto',None),
|
||||
cellSize = ('5x5',None),
|
||||
anchor = ('sw', None),
|
||||
)
|
||||
def __init__(self,value='Hello Cruel World!', **kwds):
|
||||
self.pylibdmtx_check()
|
||||
self.value = value
|
||||
for k,(d,c) in self._defaults.items():
|
||||
v = kwds.pop(k,d)
|
||||
if c: v = c(v)
|
||||
setattr(self,k,v)
|
||||
|
||||
def rect(self, x, y, w, h, fill=1, stroke=0):
|
||||
self._gadd(Rect(x,y,w,h,strokeColor=None,fillColor=self._fillColor))
|
||||
|
||||
def saveState(self,*args,**kwds):
|
||||
pass
|
||||
|
||||
restoreState = setStrokeColor = saveState
|
||||
|
||||
def setFillColor(self,c):
|
||||
self._fillColor = c
|
||||
|
||||
def draw(self):
|
||||
m = DataMatrix(value=self.value,**{k: getattr(self,k) for k in self._defaults})
|
||||
m.canv = self
|
||||
m.y += m.height
|
||||
g = Group()
|
||||
self._gadd = g.add
|
||||
m.draw()
|
||||
return g
|
||||
@@ -0,0 +1,574 @@
|
||||
__all__=(
|
||||
'Ean13BarcodeWidget','isEanString',
|
||||
'Ean8BarcodeWidget', 'UPCA', 'Ean5BarcodeWidget', 'ISBNBarcodeWidget',
|
||||
)
|
||||
from reportlab.graphics.shapes import Group, String, Rect
|
||||
from reportlab.lib import colors
|
||||
from reportlab.pdfbase.pdfmetrics import stringWidth
|
||||
from reportlab.lib.validators import isNumber, isColor, isString, Validator, isBoolean, NoneOr
|
||||
from reportlab.lib.attrmap import *
|
||||
from reportlab.graphics.charts.areas import PlotArea
|
||||
from reportlab.lib.units import mm
|
||||
from reportlab.lib.utils import asNative
|
||||
|
||||
#work out a list of manufacturer codes....
|
||||
_eanNumberSystems = [
|
||||
('00-13', 'USA & Canada'),
|
||||
('20-29', 'In-Store Functions'),
|
||||
('30-37', 'France'),
|
||||
('40-44', 'Germany'),
|
||||
('45', 'Japan (also 49)'),
|
||||
('46', 'Russian Federation'),
|
||||
('471', 'Taiwan'),
|
||||
('474', 'Estonia'),
|
||||
('475', 'Latvia'),
|
||||
('477', 'Lithuania'),
|
||||
('479', 'Sri Lanka'),
|
||||
('480', 'Philippines'),
|
||||
('482', 'Ukraine'),
|
||||
('484', 'Moldova'),
|
||||
('485', 'Armenia'),
|
||||
('486', 'Georgia'),
|
||||
('487', 'Kazakhstan'),
|
||||
('489', 'Hong Kong'),
|
||||
('49', 'Japan (JAN-13)'),
|
||||
('50', 'United Kingdom'),
|
||||
('520', 'Greece'),
|
||||
('528', 'Lebanon'),
|
||||
('529', 'Cyprus'),
|
||||
('531', 'Macedonia'),
|
||||
('535', 'Malta'),
|
||||
('539', 'Ireland'),
|
||||
('54', 'Belgium & Luxembourg'),
|
||||
('560', 'Portugal'),
|
||||
('569', 'Iceland'),
|
||||
('57', 'Denmark'),
|
||||
('590', 'Poland'),
|
||||
('594', 'Romania'),
|
||||
('599', 'Hungary'),
|
||||
('600-601', 'South Africa'),
|
||||
('609', 'Mauritius'),
|
||||
('611', 'Morocco'),
|
||||
('613', 'Algeria'),
|
||||
('619', 'Tunisia'),
|
||||
('622', 'Egypt'),
|
||||
('625', 'Jordan'),
|
||||
('626', 'Iran'),
|
||||
('64', 'Finland'),
|
||||
('690-692', 'China'),
|
||||
('70', 'Norway'),
|
||||
('729', 'Israel'),
|
||||
('73', 'Sweden'),
|
||||
('740', 'Guatemala'),
|
||||
('741', 'El Salvador'),
|
||||
('742', 'Honduras'),
|
||||
('743', 'Nicaragua'),
|
||||
('744', 'Costa Rica'),
|
||||
('746', 'Dominican Republic'),
|
||||
('750', 'Mexico'),
|
||||
('759', 'Venezuela'),
|
||||
('76', 'Switzerland'),
|
||||
('770', 'Colombia'),
|
||||
('773', 'Uruguay'),
|
||||
('775', 'Peru'),
|
||||
('777', 'Bolivia'),
|
||||
('779', 'Argentina'),
|
||||
('780', 'Chile'),
|
||||
('784', 'Paraguay'),
|
||||
('785', 'Peru'),
|
||||
('786', 'Ecuador'),
|
||||
('789', 'Brazil'),
|
||||
('80-83', 'Italy'),
|
||||
('84', 'Spain'),
|
||||
('850', 'Cuba'),
|
||||
('858', 'Slovakia'),
|
||||
('859', 'Czech Republic'),
|
||||
('860', 'Yugloslavia'),
|
||||
('869', 'Turkey'),
|
||||
('87', 'Netherlands'),
|
||||
('880', 'South Korea'),
|
||||
('885', 'Thailand'),
|
||||
('888', 'Singapore'),
|
||||
('890', 'India'),
|
||||
('893', 'Vietnam'),
|
||||
('899', 'Indonesia'),
|
||||
('90-91', 'Austria'),
|
||||
('93', 'Australia'),
|
||||
('94', 'New Zealand'),
|
||||
('955', 'Malaysia'),
|
||||
('977', 'International Standard Serial Number for Periodicals (ISSN)'),
|
||||
('978', 'International Standard Book Numbering (ISBN)'),
|
||||
('979', 'International Standard Music Number (ISMN)'),
|
||||
('980', 'Refund receipts'),
|
||||
('981-982', 'Common Currency Coupons'),
|
||||
('99', 'Coupons')
|
||||
]
|
||||
|
||||
manufacturerCodes = {}
|
||||
for (k, v) in _eanNumberSystems:
|
||||
words = k.split('-')
|
||||
if len(words)==2:
|
||||
fromCode = int(words[0])
|
||||
toCode = int(words[1])
|
||||
for code in range(fromCode, toCode+1):
|
||||
manufacturerCodes[code] = v
|
||||
else:
|
||||
manufacturerCodes[int(k)] = v
|
||||
|
||||
def nDigits(n):
|
||||
class _ndigits(Validator):
|
||||
def test(self,x):
|
||||
return type(x) is str and len(x)<=n and len([c for c in x if c in "0123456789"])==n
|
||||
return _ndigits()
|
||||
|
||||
class Ean13BarcodeWidget(PlotArea):
|
||||
codeName = "EAN13"
|
||||
_attrMap = AttrMap(BASE=PlotArea,
|
||||
value = AttrMapValue(nDigits(12), desc='the number'),
|
||||
fontName = AttrMapValue(isString, desc='fontName'),
|
||||
fontSize = AttrMapValue(isNumber, desc='font size'),
|
||||
x = AttrMapValue(isNumber, desc='x-coord'),
|
||||
y = AttrMapValue(isNumber, desc='y-coord'),
|
||||
barFillColor = AttrMapValue(isColor, desc='bar color'),
|
||||
barHeight = AttrMapValue(isNumber, desc='Height of bars.'),
|
||||
barWidth = AttrMapValue(isNumber, desc='Width of bars.'),
|
||||
barStrokeWidth = AttrMapValue(isNumber, desc='Width of bar borders.'),
|
||||
barStrokeColor = AttrMapValue(isColor, desc='Color of bar borders.'),
|
||||
textColor = AttrMapValue(isColor, desc='human readable text color'),
|
||||
humanReadable = AttrMapValue(isBoolean, desc='if human readable'),
|
||||
quiet = AttrMapValue(isBoolean, desc='if quiet zone to be used'),
|
||||
lquiet = AttrMapValue(isBoolean, desc='left quiet zone length'),
|
||||
rquiet = AttrMapValue(isBoolean, desc='right quiet zone length'),
|
||||
)
|
||||
_digits=12
|
||||
_start_right = 7 #for ean-13 left = [0:7] right=[7:13]
|
||||
_nbars = 113
|
||||
barHeight = 25.93*mm #millimeters
|
||||
barWidth = (37.29/_nbars)*mm
|
||||
humanReadable = 1
|
||||
_0csw = 1
|
||||
_1csw = 3
|
||||
|
||||
#Left Hand Digits.
|
||||
_left = ( ("0001101", "0011001", "0010011", "0111101",
|
||||
"0100011", "0110001", "0101111", "0111011",
|
||||
"0110111", "0001011",
|
||||
), #odd left hand digits
|
||||
("0100111", "0110011", "0011011", "0100001",
|
||||
"0011101", "0111001", "0000101", "0010001",
|
||||
"0001001", "0010111"), #even left hand digits
|
||||
)
|
||||
|
||||
_right = ("1110010", "1100110", "1101100", "1000010",
|
||||
"1011100", "1001110", "1010000", "1000100",
|
||||
"1001000", "1110100")
|
||||
|
||||
quiet = 1
|
||||
rquiet = lquiet = None
|
||||
_tail = "101"
|
||||
_sep = "01010"
|
||||
|
||||
_lhconvert={
|
||||
"0": (0,0,0,0,0,0),
|
||||
"1": (0,0,1,0,1,1),
|
||||
"2": (0,0,1,1,0,1),
|
||||
"3": (0,0,1,1,1,0),
|
||||
"4": (0,1,0,0,1,1),
|
||||
"5": (0,1,1,0,0,1),
|
||||
"6": (0,1,1,1,0,0),
|
||||
"7": (0,1,0,1,0,1),
|
||||
"8": (0,1,0,1,1,0),
|
||||
"9": (0,1,1,0,1,0)
|
||||
}
|
||||
fontSize = 8 #millimeters
|
||||
fontName = 'Helvetica'
|
||||
textColor = barFillColor = colors.black
|
||||
barStrokeColor = None
|
||||
barStrokeWidth = 0
|
||||
x = 0
|
||||
y = 0
|
||||
def __init__(self,value='123456789012',**kw):
|
||||
value = str(value) if isinstance(value,int) else asNative(value)
|
||||
self.value=max(self._digits-len(value),0)*'0'+value[:self._digits]
|
||||
for k, v in kw.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
width = property(lambda self: self.barWidth*(self._nbars-18+self._calc_quiet(self.lquiet)+self._calc_quiet(self.rquiet)))
|
||||
|
||||
def wrap(self,aW,aH):
|
||||
return self.width,self.barHeight
|
||||
|
||||
def _encode_left(self,s,a):
|
||||
cp = self._lhconvert[s[0]] #convert the left hand numbers
|
||||
_left = self._left
|
||||
z = ord('0')
|
||||
for i,c in enumerate(s[1:self._start_right]):
|
||||
a(_left[cp[i]][ord(c)-z])
|
||||
|
||||
def _short_bar(self,i):
|
||||
i += 9 - self._lquiet
|
||||
return self.humanReadable and ((12<i<55) or (57<i<101))
|
||||
|
||||
def _calc_quiet(self,v):
|
||||
if self.quiet:
|
||||
if v is None:
|
||||
v = 9
|
||||
else:
|
||||
x = float(max(v,0))/self.barWidth
|
||||
v = int(x)
|
||||
if v-x>0: v += 1
|
||||
else:
|
||||
v = 0
|
||||
return v
|
||||
|
||||
def draw(self):
|
||||
g = Group()
|
||||
gAdd = g.add
|
||||
barWidth = self.barWidth
|
||||
width = self.width
|
||||
barHeight = self.barHeight
|
||||
x = self.x
|
||||
y = self.y
|
||||
gAdd(Rect(x,y,width,barHeight,fillColor=None,strokeColor=None,strokeWidth=0))
|
||||
s = self.value+self._checkdigit(self.value)
|
||||
self._lquiet = lquiet = self._calc_quiet(self.lquiet)
|
||||
rquiet = self._calc_quiet(self.rquiet)
|
||||
b = [lquiet*'0',self._tail] #the signal string
|
||||
a = b.append
|
||||
self._encode_left(s,a)
|
||||
a(self._sep)
|
||||
|
||||
z = ord('0')
|
||||
_right = self._right
|
||||
for c in s[self._start_right:]:
|
||||
a(_right[ord(c)-z])
|
||||
a(self._tail)
|
||||
a(rquiet*'0')
|
||||
|
||||
fontSize = self.fontSize
|
||||
barFillColor = self.barFillColor
|
||||
barStrokeWidth = self.barStrokeWidth
|
||||
barStrokeColor = self.barStrokeColor
|
||||
|
||||
fth = fontSize*1.2
|
||||
b = ''.join(b)
|
||||
|
||||
lrect = None
|
||||
for i,c in enumerate(b):
|
||||
if c=="1":
|
||||
dh = self._short_bar(i) and fth or 0
|
||||
yh = y+dh
|
||||
if lrect and lrect.y==yh:
|
||||
lrect.width += barWidth
|
||||
else:
|
||||
lrect = Rect(x,yh,barWidth,barHeight-dh,fillColor=barFillColor,strokeWidth=barStrokeWidth,strokeColor=barStrokeColor)
|
||||
gAdd(lrect)
|
||||
else:
|
||||
lrect = None
|
||||
x += barWidth
|
||||
|
||||
if self.humanReadable: self._add_human_readable(s,gAdd)
|
||||
return g
|
||||
|
||||
def _add_human_readable(self,s,gAdd):
|
||||
barWidth = self.barWidth
|
||||
fontSize = self.fontSize
|
||||
textColor = self.textColor
|
||||
fontName = self.fontName
|
||||
fth = fontSize*1.2
|
||||
# draw the num below the line.
|
||||
c = s[0]
|
||||
w = stringWidth(c,fontName,fontSize)
|
||||
x = self.x+barWidth*(self._lquiet-8)
|
||||
y = self.y + 0.2*fth
|
||||
|
||||
gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor))
|
||||
x = self.x + (33-9+self._lquiet)*barWidth
|
||||
|
||||
c = s[1:7]
|
||||
gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor,textAnchor='middle'))
|
||||
|
||||
x += 47*barWidth
|
||||
c = s[7:]
|
||||
gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor,textAnchor='middle'))
|
||||
|
||||
def _checkdigit(cls,num):
|
||||
z = ord('0')
|
||||
iSum = cls._0csw*sum([(ord(x)-z) for x in num[::2]]) \
|
||||
+ cls._1csw*sum([(ord(x)-z) for x in num[1::2]])
|
||||
return chr(z+((10-(iSum%10))%10))
|
||||
_checkdigit=classmethod(_checkdigit)
|
||||
|
||||
class Ean8BarcodeWidget(Ean13BarcodeWidget):
|
||||
codeName = "EAN8"
|
||||
_attrMap = AttrMap(BASE=Ean13BarcodeWidget,
|
||||
value = AttrMapValue(nDigits(7), desc='the number'),
|
||||
)
|
||||
_start_right = 4 #for ean-13 left = [0:7] right=[7:13]
|
||||
_nbars = 85
|
||||
_digits=7
|
||||
_0csw = 3
|
||||
_1csw = 1
|
||||
|
||||
def _encode_left(self,s,a):
|
||||
cp = self._lhconvert[s[0]] #convert the left hand numbers
|
||||
_left = self._left[0]
|
||||
z = ord('0')
|
||||
for i,c in enumerate(s[0:self._start_right]):
|
||||
a(_left[ord(c)-z])
|
||||
|
||||
def _short_bar(self,i):
|
||||
i += 9 - self._lquiet
|
||||
return self.humanReadable and ((12<i<41) or (43<i<73))
|
||||
|
||||
def _add_human_readable(self,s,gAdd):
|
||||
barWidth = self.barWidth
|
||||
fontSize = self.fontSize
|
||||
textColor = self.textColor
|
||||
fontName = self.fontName
|
||||
fth = fontSize*1.2
|
||||
# draw the num below the line.
|
||||
y = self.y + 0.2*fth
|
||||
|
||||
x = (26.5-9+self._lquiet)*barWidth
|
||||
|
||||
c = s[0:4]
|
||||
gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor,textAnchor='middle'))
|
||||
|
||||
x = (59.5-9+self._lquiet)*barWidth
|
||||
c = s[4:]
|
||||
gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor,textAnchor='middle'))
|
||||
|
||||
class UPCA(Ean13BarcodeWidget):
|
||||
codeName = "UPCA"
|
||||
_attrMap = AttrMap(BASE=Ean13BarcodeWidget,
|
||||
value = AttrMapValue(nDigits(11), desc='the number'),
|
||||
)
|
||||
_start_right = 6
|
||||
_digits = 11
|
||||
_0csw = 3
|
||||
_1csw = 1
|
||||
_nbars = 1+7*11+2*3+5
|
||||
|
||||
#these methods contributed by Kyle Macfarlane
|
||||
#https://bitbucket.org/kylemacfarlane/
|
||||
def _encode_left(self,s,a):
|
||||
cp = self._lhconvert[s[0]] #convert the left hand numbers
|
||||
_left = self._left[0]
|
||||
z = ord('0')
|
||||
for i,c in enumerate(s[0:self._start_right]):
|
||||
a(_left[ord(c)-z])
|
||||
|
||||
def _short_bar(self,i):
|
||||
i += 9 - self._lquiet
|
||||
return self.humanReadable and ((18<i<55) or (57<i<93))
|
||||
|
||||
def _add_human_readable(self,s,gAdd):
|
||||
barWidth = self.barWidth
|
||||
fontSize = self.fontSize
|
||||
textColor = self.textColor
|
||||
fontName = self.fontName
|
||||
fth = fontSize*1.2
|
||||
# draw the num below the line.
|
||||
c = s[0]
|
||||
w = stringWidth(c,fontName,fontSize)
|
||||
x = self.x+barWidth*(self._lquiet-8)
|
||||
y = self.y + 0.2*fth
|
||||
|
||||
gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor))
|
||||
x = self.x + (38-9+self._lquiet)*barWidth
|
||||
|
||||
c = s[1:6]
|
||||
gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor,textAnchor='middle'))
|
||||
|
||||
x += 36*barWidth
|
||||
c = s[6:11]
|
||||
gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor,textAnchor='middle'))
|
||||
|
||||
x += 32*barWidth
|
||||
c = s[11]
|
||||
gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor))
|
||||
|
||||
class Ean5BarcodeWidget(Ean13BarcodeWidget):
|
||||
"""
|
||||
EAN-5 barcodes can print the human readable price, set:
|
||||
price=True
|
||||
"""
|
||||
codeName = "EAN5"
|
||||
_attrMap = AttrMap(BASE=Ean13BarcodeWidget,
|
||||
price=AttrMapValue(isBoolean,
|
||||
desc='whether to display the price or not'),
|
||||
value=AttrMapValue(nDigits(5), desc='the number'),
|
||||
)
|
||||
_nbars = 48
|
||||
_digits = 5
|
||||
_sep = '01'
|
||||
_tail = '01011'
|
||||
_0csw = 3
|
||||
_1csw = 9
|
||||
|
||||
_lhconvert = {
|
||||
"0": (1, 1, 0, 0, 0),
|
||||
"1": (1, 0, 1, 0, 0),
|
||||
"2": (1, 0, 0, 1, 0),
|
||||
"3": (1, 0, 0, 0, 1),
|
||||
"4": (0, 1, 1, 0, 0),
|
||||
"5": (0, 0, 1, 1, 0),
|
||||
"6": (0, 0, 0, 1, 1),
|
||||
"7": (0, 1, 0, 1, 0),
|
||||
"8": (0, 1, 0, 0, 1),
|
||||
"9": (0, 0, 1, 0, 1)
|
||||
}
|
||||
|
||||
def _checkdigit(cls, num):
|
||||
z = ord('0')
|
||||
iSum = cls._0csw * sum([(ord(x) - z) for x in num[::2]]) \
|
||||
+ cls._1csw * sum([(ord(x) - z) for x in num[1::2]])
|
||||
return chr(z + iSum % 10)
|
||||
|
||||
def _encode_left(self, s, a):
|
||||
check = self._checkdigit(s)
|
||||
cp = self._lhconvert[check]
|
||||
_left = self._left
|
||||
_sep = self._sep
|
||||
z = ord('0')
|
||||
full_code = []
|
||||
for i, c in enumerate(s):
|
||||
full_code.append(_left[cp[i]][ord(c) - z])
|
||||
a(_sep.join(full_code))
|
||||
|
||||
def _short_bar(self, i):
|
||||
i += 9 - self._lquiet
|
||||
return self.humanReadable and ((12 < i < 41) or (43 < i < 73))
|
||||
|
||||
def _add_human_readable(self, s, gAdd):
|
||||
barWidth = self.barWidth
|
||||
fontSize = self.fontSize
|
||||
textColor = self.textColor
|
||||
fontName = self.fontName
|
||||
fth = fontSize * 1.2
|
||||
# draw the num below the line.
|
||||
y = self.y + 0.2 * fth
|
||||
|
||||
x = self.x + (self._nbars + self._lquiet * 2) * barWidth / 2
|
||||
|
||||
gAdd(String(x, y, s, fontName=fontName, fontSize=fontSize,
|
||||
fillColor=textColor, textAnchor='middle'))
|
||||
|
||||
price = getattr(self,'price',None)
|
||||
if price:
|
||||
price = None
|
||||
if s[0] in '3456':
|
||||
price = '$'
|
||||
elif s[0] in '01':
|
||||
price = asNative(b'\xc2\xa3')
|
||||
|
||||
if price is None:
|
||||
return
|
||||
|
||||
price += s[1:3] + '.' + s[3:5]
|
||||
y += self.barHeight
|
||||
gAdd(String(x, y, price, fontName=fontName, fontSize=fontSize,
|
||||
fillColor=textColor, textAnchor='middle'))
|
||||
|
||||
def draw(self):
|
||||
g = Group()
|
||||
gAdd = g.add
|
||||
barWidth = self.barWidth
|
||||
width = self.width
|
||||
barHeight = self.barHeight
|
||||
x = self.x
|
||||
y = self.y
|
||||
gAdd(Rect(x, y, width, barHeight, fillColor=None, strokeColor=None,
|
||||
strokeWidth=0))
|
||||
s = self.value
|
||||
self._lquiet = lquiet = self._calc_quiet(self.lquiet)
|
||||
rquiet = self._calc_quiet(self.rquiet)
|
||||
b = [lquiet * '0' + self._tail] # the signal string
|
||||
a = b.append
|
||||
self._encode_left(s, a)
|
||||
|
||||
a(rquiet * '0')
|
||||
|
||||
fontSize = self.fontSize
|
||||
barFillColor = self.barFillColor
|
||||
barStrokeWidth = self.barStrokeWidth
|
||||
barStrokeColor = self.barStrokeColor
|
||||
|
||||
fth = fontSize * 1.2
|
||||
b = ''.join(b)
|
||||
|
||||
lrect = None
|
||||
for i, c in enumerate(b):
|
||||
if c == "1":
|
||||
dh = fth
|
||||
yh = y + dh
|
||||
if lrect and lrect.y == yh:
|
||||
lrect.width += barWidth
|
||||
else:
|
||||
lrect = Rect(x, yh, barWidth, barHeight - dh,
|
||||
fillColor=barFillColor,
|
||||
strokeWidth=barStrokeWidth,
|
||||
strokeColor=barStrokeColor)
|
||||
gAdd(lrect)
|
||||
else:
|
||||
lrect = None
|
||||
x += barWidth
|
||||
|
||||
if self.humanReadable:
|
||||
self._add_human_readable(s, gAdd)
|
||||
return g
|
||||
|
||||
class ISBNBarcodeWidget(Ean13BarcodeWidget):
|
||||
"""
|
||||
ISBN Barcodes optionally print the EAN-5 supplemental price
|
||||
barcode (with the price in dollars or pounds). Set price to a string
|
||||
that follows the EAN-5 for ISBN spec:
|
||||
|
||||
leading digit 0, 1 = GBP
|
||||
3 = AUD
|
||||
4 = NZD
|
||||
5 = USD
|
||||
6 = CAD
|
||||
next 4 digits = price between 00.00 and 99.98, i.e.:
|
||||
|
||||
price='52499' # $24.99 USD
|
||||
"""
|
||||
codeName = 'ISBN'
|
||||
_attrMap = AttrMap(BASE=Ean13BarcodeWidget,
|
||||
price=AttrMapValue(
|
||||
NoneOr(nDigits(5)),
|
||||
desc='None or the price to display'),
|
||||
)
|
||||
def draw(self):
|
||||
g = Ean13BarcodeWidget.draw(self)
|
||||
|
||||
price = getattr(self,'price',None)
|
||||
if not price:
|
||||
return g
|
||||
|
||||
bounds = g.getBounds()
|
||||
x = bounds[2]
|
||||
pricecode = Ean5BarcodeWidget(x=x, value=price, price=True,
|
||||
humanReadable=True,
|
||||
barHeight=self.barHeight, quiet=self.quiet)
|
||||
g.add(pricecode)
|
||||
return g
|
||||
|
||||
def _add_human_readable(self, s, gAdd):
|
||||
Ean13BarcodeWidget._add_human_readable(self,s, gAdd)
|
||||
barWidth = self.barWidth
|
||||
barHeight = self.barHeight
|
||||
fontSize = self.fontSize
|
||||
textColor = self.textColor
|
||||
fontName = self.fontName
|
||||
fth = fontSize * 1.2
|
||||
y = self.y + 0.2 * fth + barHeight
|
||||
x = self._lquiet * barWidth
|
||||
|
||||
isbn = 'ISBN '
|
||||
segments = [s[0:3], s[3:4], s[4:9], s[9:12], s[12]]
|
||||
isbn += '-'.join(segments)
|
||||
|
||||
gAdd(String(x, y, isbn, fontName=fontName, fontSize=fontSize,
|
||||
fillColor=textColor))
|
||||
@@ -0,0 +1,445 @@
|
||||
#this code contributed by Kyle Macfarlane see
|
||||
#https://bitbucket.org/rptlab/reportlab/issues/69/implementations-of-code-128-auto-and-data
|
||||
__all__= ('ECC200datamatrix',)
|
||||
FACTORS = {
|
||||
5: (228, 48, 15, 111, 62),
|
||||
7: (23, 68, 144, 134, 240, 92, 254),
|
||||
10: (28, 24, 185, 166, 223, 248, 116, 255, 110, 61),
|
||||
11: (175, 138, 205, 12, 194, 168, 39, 245, 60, 97, 120),
|
||||
12: (41, 153, 158, 91, 61, 42, 142, 213, 97, 178, 100, 242),
|
||||
14: (156, 97, 192, 252, 95, 9, 157, 119, 138, 45, 18, 186, 83, 185),
|
||||
18: (83, 195, 100, 39, 188, 75, 66, 61, 241, 213, 109, 129,
|
||||
94, 254, 225, 48, 90, 188),
|
||||
20: (15, 195, 244, 9, 233, 71, 168, 2, 188, 160, 153, 145,
|
||||
253, 79, 108, 82, 27, 174, 186, 172),
|
||||
24: (52, 190, 88, 205, 109, 39, 176, 21, 155, 197, 251, 223, 155,
|
||||
21, 5, 172, 254, 124, 12, 181, 184, 96, 50, 193),
|
||||
28: (211, 231, 43, 97, 71, 96, 103, 174, 37, 151, 170, 53, 75, 34,
|
||||
249, 121, 17, 138, 110, 213, 141, 136, 120, 151, 233, 168, 93, 255),
|
||||
36: (245, 127, 242, 218, 130, 250, 162, 181, 102, 120, 84, 179, 220, 251,
|
||||
80, 182, 229, 18, 2, 4, 68, 33, 101, 137, 95, 119, 115, 44,
|
||||
175, 184, 59, 25, 225, 98, 81, 112),
|
||||
42: (77, 193, 137, 31, 19, 38, 22, 153, 247, 105, 122, 2, 245, 133,
|
||||
242, 8, 175, 95, 100, 9, 167, 105, 214, 111, 57, 121, 21,
|
||||
1, 253, 57, 54, 101, 248, 202, 69, 50, 150, 177, 226, 5, 9, 5),
|
||||
48: (245, 132, 172, 223, 96, 32, 117, 22, 238, 133, 238, 231, 205, 188,
|
||||
237, 87, 191, 106, 16, 147, 118, 23, 37, 90, 170, 205, 131, 88,
|
||||
120, 100, 66, 138, 186, 240, 82, 44, 176, 87, 187, 147, 160, 175,
|
||||
69, 213, 92, 253, 225, 19),
|
||||
56: (175, 9, 223, 238, 12, 17, 220, 208, 100, 29, 175, 170, 230, 192,
|
||||
215, 235, 150, 159, 36, 223, 38, 200, 132, 54, 228, 146, 218, 234,
|
||||
117, 203, 29, 232, 144, 238, 22, 150, 201, 117, 62, 207, 164, 13,
|
||||
137, 245, 127, 67, 247, 28, 155, 43, 203, 107, 233, 53, 143, 46),
|
||||
62: (242, 93, 169, 50, 144, 210, 39, 118, 202, 188, 201, 189, 143, 108,
|
||||
196, 37, 185, 112, 134, 230, 245, 63, 197, 190, 250, 106, 185, 221,
|
||||
175, 64, 114, 71, 161, 44, 147, 6, 27, 218, 51, 63, 87, 10,
|
||||
40, 130, 188, 17, 163, 31, 176, 170, 4, 107, 232, 7, 94, 166,
|
||||
224, 124, 86, 47, 11, 204),
|
||||
68: (220, 228, 173, 89, 251, 149, 159, 56, 89, 33, 147, 244, 154, 36,
|
||||
73, 127, 213, 136, 248, 180, 234, 197, 158, 177, 68, 122, 93, 213,
|
||||
15, 160, 227, 236, 66, 139, 153, 185, 202, 167, 179, 25, 220, 232,
|
||||
96, 210, 231, 136, 223, 239, 181, 241, 59, 52, 172, 25, 49, 232,
|
||||
211, 189, 64, 54, 108, 153, 132, 63, 96, 103, 82, 186)
|
||||
}
|
||||
|
||||
LOGVAL = (
|
||||
-255, 255, 1, 240, 2, 225, 241, 53, 3, 38, 226, 133, 242, 43,
|
||||
54, 210, 4, 195, 39, 114, 227, 106, 134, 28, 243, 140, 44, 23,
|
||||
55, 118, 211, 234, 5, 219, 196, 96, 40, 222, 115, 103, 228, 78,
|
||||
107, 125, 135, 8, 29, 162, 244, 186, 141, 180, 45, 99, 24, 49,
|
||||
56, 13, 119, 153, 212, 199, 235, 91, 6, 76, 220, 217, 197, 11,
|
||||
97, 184, 41, 36, 223, 253, 116, 138, 104, 193, 229, 86, 79, 171,
|
||||
108, 165, 126, 145, 136, 34, 9, 74, 30, 32, 163, 84, 245, 173,
|
||||
187, 204, 142, 81, 181, 190, 46, 88, 100, 159, 25, 231, 50, 207,
|
||||
57, 147, 14, 67, 120, 128, 154, 248, 213, 167, 200, 63, 236, 110,
|
||||
92, 176, 7, 161, 77, 124, 221, 102, 218, 95, 198, 90, 12, 152,
|
||||
98, 48, 185, 179, 42, 209, 37, 132, 224, 52, 254, 239, 117, 233,
|
||||
139, 22, 105, 27, 194, 113, 230, 206, 87, 158, 80, 189, 172, 203,
|
||||
109, 175, 166, 62, 127, 247, 146, 66, 137, 192, 35, 252, 10, 183,
|
||||
75, 216, 31, 83, 33, 73, 164, 144, 85, 170, 246, 65, 174, 61,
|
||||
188, 202, 205, 157, 143, 169, 82, 72, 182, 215, 191, 251, 47, 178,
|
||||
89, 151, 101, 94, 160, 123, 26, 112, 232, 21, 51, 238, 208, 131,
|
||||
58, 69, 148, 18, 15, 16, 68, 17, 121, 149, 129, 19, 155, 59,
|
||||
249, 70, 214, 250, 168, 71, 201, 156, 64, 60, 237, 130, 111, 20,
|
||||
93, 122, 177, 150
|
||||
)
|
||||
|
||||
ALOGVAL = (
|
||||
1, 2, 4, 8, 16, 32, 64, 128, 45, 90, 180, 69, 138, 57,
|
||||
114, 228, 229, 231, 227, 235, 251, 219, 155, 27, 54, 108, 216, 157,
|
||||
23, 46, 92, 184, 93, 186, 89, 178, 73, 146, 9, 18, 36, 72,
|
||||
144, 13, 26, 52, 104, 208, 141, 55, 110, 220, 149, 7, 14, 28,
|
||||
56, 112, 224, 237, 247, 195, 171, 123, 246, 193, 175, 115, 230, 225,
|
||||
239, 243, 203, 187, 91, 182, 65, 130, 41, 82, 164, 101, 202, 185,
|
||||
95, 190, 81, 162, 105, 210, 137, 63, 126, 252, 213, 135, 35, 70,
|
||||
140, 53, 106, 212, 133, 39, 78, 156, 21, 42, 84, 168, 125, 250,
|
||||
217, 159, 19, 38, 76, 152, 29, 58, 116, 232, 253, 215, 131, 43,
|
||||
86, 172, 117, 234, 249, 223, 147, 11, 22, 44, 88, 176, 77, 154,
|
||||
25, 50, 100, 200, 189, 87, 174, 113, 226, 233, 255, 211, 139, 59,
|
||||
118, 236, 245, 199, 163, 107, 214, 129, 47, 94, 188, 85, 170, 121,
|
||||
242, 201, 191, 83, 166, 97, 194, 169, 127, 254, 209, 143, 51, 102,
|
||||
204, 181, 71, 142, 49, 98, 196, 165, 103, 206, 177, 79, 158, 17,
|
||||
34, 68, 136, 61, 122, 244, 197, 167, 99, 198, 161, 111, 222, 145,
|
||||
15, 30, 60, 120, 240, 205, 183, 67, 134, 33, 66, 132, 37, 74,
|
||||
148, 5, 10, 20, 40, 80, 160, 109, 218, 153, 31, 62, 124, 248,
|
||||
221, 151, 3, 6, 12, 24, 48, 96, 192, 173, 119, 238, 241, 207,
|
||||
179, 75, 150, 1
|
||||
)
|
||||
|
||||
from reportlab.graphics.barcode.common import Barcode
|
||||
class ECC200DataMatrix(Barcode):
|
||||
'''This code only supports a Type 12 (44x44) C40 encoded data matrix.
|
||||
This is the size and encoding that Royal Mail wants on all mail from October 1st 2015.
|
||||
see https://bitbucket.org/rptlab/reportlab/issues/69/implementations-of-code-128-auto-and-data
|
||||
'''
|
||||
barWidth = 4
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
Barcode.__init__(self,*args, **kwargs)
|
||||
|
||||
# These values below are hardcoded for a Type 12 44x44 data matrix
|
||||
self.row_modules = 44
|
||||
self.col_modules = 44
|
||||
self.row_regions = 2
|
||||
self.col_regions = 2
|
||||
self.cw_data = 144
|
||||
self.cw_ecc = 56
|
||||
self.row_usable_modules = self.row_modules - self.row_regions * 2
|
||||
self.col_usable_modules = self.col_modules - self.col_regions * 2
|
||||
|
||||
def validate(self):
|
||||
self.valid = 1
|
||||
for c in self.value:
|
||||
if ord(c) > 255:
|
||||
self.valid = 0
|
||||
break
|
||||
else:
|
||||
self.validated = self.value
|
||||
|
||||
def _encode_c40_char(self, char):
|
||||
o = ord(char)
|
||||
encoded = []
|
||||
|
||||
if o == 32 or (o >= 48 and o <= 57) or (o >= 65 and o <= 90):
|
||||
# Stay in set 0
|
||||
if o == 32:
|
||||
encoded.append(o - 29)
|
||||
elif o >= 48 and o <= 57:
|
||||
encoded.append(o - 44)
|
||||
else:
|
||||
encoded.append(o - 51)
|
||||
elif o >= 0 and o <= 31:
|
||||
encoded.append(0) # Shift to set 1
|
||||
encoded.append(o)
|
||||
elif (o >= 33 and o <= 64) or (o >= 91 and o <= 95):
|
||||
encoded.append(1) # Shift to set 2
|
||||
if o >= 33 and o <= 64:
|
||||
encoded.append(o - 33)
|
||||
else:
|
||||
encoded.append(o - 69)
|
||||
elif o >= 96 and o <= 127:
|
||||
encoded.append(2) # Shift to set 3
|
||||
encoded.append(o - 96)
|
||||
elif o >= 128 and o <= 255:
|
||||
# Extended ASCII
|
||||
encoded.append(1) # Shift to set 2
|
||||
encoded.append(30) # Upper shift / hibit
|
||||
encoded += self._encode_c40_char(chr(o - 128))
|
||||
else:
|
||||
raise Exception('Cannot encode %s (%s)' % (char, o))
|
||||
|
||||
return encoded
|
||||
|
||||
def _encode_c40(self, value):
|
||||
encoded = []
|
||||
|
||||
for c in value:
|
||||
encoded += self._encode_c40_char(c)
|
||||
|
||||
while len(encoded) % 3:
|
||||
encoded.append(0) # Fake padding that makes chunking in the next step easier
|
||||
|
||||
codewords = []
|
||||
codewords.append(230) # Switch to C40 encoding
|
||||
|
||||
for i in range(0, len(encoded), 3):
|
||||
chunk = encoded[i:i+3]
|
||||
total = chunk[0] * 1600 + chunk[1] * 40 + chunk[2] + 1
|
||||
codewords.append(total // 256)
|
||||
codewords.append(total % 256)
|
||||
|
||||
codewords.append(254) # End of data
|
||||
|
||||
if len(codewords) > self.cw_data:
|
||||
raise Exception('Too much data to fit into a data matrix of this size')
|
||||
|
||||
if len(codewords) < self.cw_data:
|
||||
# Real padding
|
||||
codewords.append(129) # Start padding
|
||||
while len(codewords) < self.cw_data:
|
||||
r = ((149 * (len(codewords) + 1)) % 253) + 1
|
||||
codewords.append((129 + r) % 254)
|
||||
|
||||
return codewords
|
||||
|
||||
def _gfsum(self, int1, int2):
|
||||
return int1 ^ int2
|
||||
|
||||
def _gfproduct(self, int1, int2):
|
||||
if int1 == 0 or int2 == 0:
|
||||
return 0
|
||||
else:
|
||||
return ALOGVAL[(LOGVAL[int1] + LOGVAL[int2]) % 255]
|
||||
|
||||
def _get_reed_solomon_code(self, data, num_code_words):
|
||||
"""
|
||||
This method is basically verbatim from "huBarcode" which is BSD licensed
|
||||
https://github.com/hudora/huBarcode/blob/master/hubarcode/datamatrix/reedsolomon.py
|
||||
"""
|
||||
cw_factors = FACTORS[num_code_words]
|
||||
code_words = [0] * num_code_words
|
||||
|
||||
for data_word in data:
|
||||
tmp = self._gfsum(data_word, code_words[-1])
|
||||
for j in range(num_code_words - 1, -1, -1):
|
||||
code_words[j] = self._gfproduct(tmp, cw_factors[j])
|
||||
if j > 0:
|
||||
code_words[j] = self._gfsum(code_words[j - 1], code_words[j])
|
||||
|
||||
code_words.reverse()
|
||||
return code_words
|
||||
|
||||
def _get_next_bits(self, data):
|
||||
value = data.pop(0)
|
||||
bits = []
|
||||
for i in range(0, 8):
|
||||
bits.append(value >> i & 1)
|
||||
bits.reverse()
|
||||
return bits
|
||||
|
||||
def _place_bit(self, row, col, bit):
|
||||
if row < 0:
|
||||
row += self.row_usable_modules
|
||||
col += (4 - ((self.row_usable_modules + 4) % 8))
|
||||
|
||||
if col < 0:
|
||||
col += self.col_usable_modules
|
||||
row += (4 - ((self.col_usable_modules + 4) % 8))
|
||||
|
||||
self._matrix[row][col] = bit
|
||||
|
||||
def _place_bit_corner_1(self, data):
|
||||
bits = self._get_next_bits(data)
|
||||
self._place_bit(self.row_usable_modules - 1, 0, bits[0])
|
||||
self._place_bit(self.row_usable_modules - 1, 1, bits[1])
|
||||
self._place_bit(self.row_usable_modules - 1, 2, bits[2])
|
||||
self._place_bit(0, self.col_usable_modules - 2, bits[3])
|
||||
self._place_bit(0, self.col_usable_modules - 1, bits[4])
|
||||
self._place_bit(1, self.col_usable_modules - 1, bits[5])
|
||||
self._place_bit(2, self.col_usable_modules - 1, bits[6])
|
||||
self._place_bit(3, self.col_usable_modules - 1, bits[7])
|
||||
|
||||
def _place_bit_corner_2(self, data):
|
||||
bits = self._get_next_bits(data)
|
||||
self._place_bit(self.row_usable_modules - 3, 0, bits[0])
|
||||
self._place_bit(self.row_usable_modules - 2, 0, bits[1])
|
||||
self._place_bit(self.row_usable_modules - 1, 0, bits[2])
|
||||
self._place_bit(0, self.col_usable_modules - 4, bits[3])
|
||||
self._place_bit(0, self.col_usable_modules - 3, bits[4])
|
||||
self._place_bit(0, self.col_usable_modules - 2, bits[5])
|
||||
self._place_bit(0, self.col_usable_modules - 1, bits[6])
|
||||
self._place_bit(1, self.col_usable_modules - 1, bits[7])
|
||||
|
||||
def _place_bit_corner_3(self, data):
|
||||
bits = self._get_next_bits(data)
|
||||
self._place_bit(self.row_usable_modules - 3, 0, bits[0])
|
||||
self._place_bit(self.row_usable_modules - 2, 0, bits[1])
|
||||
self._place_bit(self.row_usable_modules - 1, 0, bits[2])
|
||||
self._place_bit(0, self.col_usable_modules - 2, bits[3])
|
||||
self._place_bit(0, self.col_usable_modules - 1, bits[4])
|
||||
self._place_bit(1, self.col_usable_modules - 1, bits[5])
|
||||
self._place_bit(2, self.col_usable_modules - 1, bits[6])
|
||||
self._place_bit(3, self.col_usable_modules - 1, bits[7])
|
||||
|
||||
def _place_bit_corner_4(self, data):
|
||||
bits = self._get_next_bits(data)
|
||||
self._place_bit(self.row_usable_modules - 1, 0, bits[0])
|
||||
self._place_bit(self.row_usable_modules - 1, self.col_usable_modules - 1, bits[1])
|
||||
self._place_bit(0, self.col_usable_modules - 3, bits[2])
|
||||
self._place_bit(0, self.col_usable_modules - 2, bits[3])
|
||||
self._place_bit(0, self.col_usable_modules - 1, bits[4])
|
||||
self._place_bit(1, self.col_usable_modules - 3, bits[5])
|
||||
self._place_bit(1, self.col_usable_modules - 2, bits[6])
|
||||
self._place_bit(1, self.col_usable_modules - 1, bits[7])
|
||||
|
||||
def _place_bit_standard(self, data, row, col):
|
||||
bits = self._get_next_bits(data)
|
||||
self._place_bit(row - 2, col - 2, bits[0])
|
||||
self._place_bit(row - 2, col - 1, bits[1])
|
||||
self._place_bit(row - 1, col - 2, bits[2])
|
||||
self._place_bit(row - 1, col - 1, bits[3])
|
||||
self._place_bit(row - 1, col, bits[4])
|
||||
self._place_bit(row, col - 2, bits[5])
|
||||
self._place_bit(row, col - 1, bits[6])
|
||||
self._place_bit(row, col, bits[7])
|
||||
|
||||
def _create_matrix(self, data):
|
||||
"""
|
||||
This method is heavily influenced by "huBarcode" which is BSD licensed
|
||||
https://github.com/hudora/huBarcode/blob/master/hubarcode/datamatrix/placement.py
|
||||
"""
|
||||
rows = self.row_usable_modules
|
||||
cols = self.col_usable_modules
|
||||
|
||||
self._matrix = self._create_empty_matrix(rows, cols)
|
||||
|
||||
row = 4
|
||||
col = 0
|
||||
|
||||
while True:
|
||||
if row == rows and col == 0:
|
||||
self._place_bit_corner_1(data)
|
||||
elif row == (rows - 2) and col == 0 and (cols % 4):
|
||||
self._place_bit_corner_2(data)
|
||||
elif row == (rows - 2) and col == 0 and (cols % 8 == 4):
|
||||
self._place_bit_corner_3(data)
|
||||
elif row == (rows + 4) and col == 2 and (cols % 8 == 0):
|
||||
self._place_bit_corner_4(data)
|
||||
|
||||
while True:
|
||||
if row < rows and col >= 0 and self._matrix[row][col] is None:
|
||||
self._place_bit_standard(data, row, col)
|
||||
|
||||
row -= 2
|
||||
col += 2
|
||||
|
||||
if row < 0 or col >= cols:
|
||||
break
|
||||
|
||||
row += 1
|
||||
col += 3
|
||||
|
||||
while True:
|
||||
if row >= 0 and col < cols and self._matrix[row][col] is None:
|
||||
self._place_bit_standard(data, row, col)
|
||||
|
||||
row += 2
|
||||
col -= 2
|
||||
|
||||
if row >= rows or col < 0:
|
||||
break
|
||||
|
||||
row += 3
|
||||
col += 1
|
||||
|
||||
if row >= rows and col >= cols:
|
||||
break
|
||||
|
||||
for row in self._matrix:
|
||||
for i in range(0, cols):
|
||||
if row[i] is None:
|
||||
row[i] = 0
|
||||
|
||||
return self._matrix
|
||||
|
||||
def _create_data_regions(self, matrix):
|
||||
regions = []
|
||||
col_offset = 0
|
||||
row_offset = 0
|
||||
|
||||
rows = int(self.row_usable_modules / self.row_regions)
|
||||
cols = int(self.col_usable_modules / self.col_regions)
|
||||
|
||||
while col_offset < self.row_regions:
|
||||
while row_offset < self.col_regions:
|
||||
r_offset = col_offset * rows
|
||||
c_offset = row_offset * cols
|
||||
region = matrix[r_offset:rows+r_offset]
|
||||
for i in range(0, len(region)):
|
||||
region[i] = region[i][c_offset:cols+c_offset]
|
||||
regions.append(region)
|
||||
row_offset += 1
|
||||
row_offset = 0
|
||||
col_offset += 1
|
||||
|
||||
return regions
|
||||
|
||||
def _create_empty_matrix(self, row, col):
|
||||
matrix = []
|
||||
for i in range(0, row):
|
||||
matrix.append([None] * col)
|
||||
return matrix
|
||||
|
||||
def _wrap_data_regions_with_finders(self, regions):
|
||||
wrapped = []
|
||||
|
||||
for region in regions:
|
||||
matrix = self._create_empty_matrix(
|
||||
int(self.col_modules / self.col_regions),
|
||||
int(self.row_modules / self.row_regions)
|
||||
)
|
||||
|
||||
for i, rows in enumerate(region):
|
||||
for j, data in enumerate(rows):
|
||||
matrix[i+1][j+1] = data
|
||||
|
||||
for i, row in enumerate(matrix):
|
||||
if i == 0:
|
||||
for j, col in enumerate(row):
|
||||
row[j] = (j + 1) % 2
|
||||
elif i + 1 == len(matrix):
|
||||
for j, col in enumerate(row):
|
||||
row[j] = 1
|
||||
else:
|
||||
row[0] = 1
|
||||
row[-1] = i % 2
|
||||
|
||||
wrapped.append(matrix)
|
||||
|
||||
return wrapped
|
||||
|
||||
def _merge_data_regions(self, regions):
|
||||
merged = []
|
||||
|
||||
for i in range(0, len(regions), self.row_regions):
|
||||
chunk = regions[i:i+self.row_regions]
|
||||
j = 0
|
||||
while j < len(chunk[0]):
|
||||
merged_row = []
|
||||
for row in chunk:
|
||||
merged_row += row[j]
|
||||
merged.append(merged_row)
|
||||
j += 1
|
||||
|
||||
return merged
|
||||
|
||||
def encode(self):
|
||||
if hasattr(self, 'encoded'):
|
||||
return self.encoded
|
||||
|
||||
encoded = self._encode_c40(self.validated)
|
||||
encoded += self._get_reed_solomon_code(encoded, self.cw_ecc)
|
||||
|
||||
matrix = self._create_matrix(encoded)
|
||||
data_regions = self._create_data_regions(matrix)
|
||||
wrapped = self._wrap_data_regions_with_finders(data_regions)
|
||||
self.encoded = self._merge_data_regions(wrapped)
|
||||
|
||||
self.encoded.reverse() # Helpful since PDFs start at bottom left corner
|
||||
|
||||
return self.encoded
|
||||
|
||||
def computeSize(self, *args):
|
||||
self._height = self.row_modules * self.barWidth
|
||||
self._width = self.col_modules * self.barWidth
|
||||
|
||||
def draw(self):
|
||||
for y, row in enumerate(self.encoded):
|
||||
for x, data in enumerate(row):
|
||||
if data:
|
||||
self.rect(
|
||||
self.x + x * self.barWidth,
|
||||
self.y + y * self.barWidth,
|
||||
self.barWidth,
|
||||
self.barWidth
|
||||
)
|
||||
@@ -0,0 +1,77 @@
|
||||
#
|
||||
# Copyright (c) 2000 Tyler C. Sarna <tsarna@sarna.org>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by Tyler C. Sarna.
|
||||
# 4. Neither the name of the author nor the names of contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
# . 3 T Tracker
|
||||
# , 2 D Descender
|
||||
# ' 1 A Ascender
|
||||
# | 0 H Ascender/Descender
|
||||
|
||||
_rm_patterns = {
|
||||
"0" : "--||", "1" : "-',|", "2" : "-'|,", "3" : "'-,|",
|
||||
"4" : "'-|,", "5" : "'',,", "6" : "-,'|", "7" : "-|-|",
|
||||
"8" : "-|',", "9" : "',-|", "A" : "',',", "B" : "'|-,",
|
||||
"C" : "-,|'", "D" : "-|,'", "E" : "-||-", "F" : "',,'",
|
||||
"G" : "',|-", "H" : "'|,-", "I" : ",-'|", "J" : ",'-|",
|
||||
"K" : ",'',", "L" : "|--|", "M" : "|-',", "N" : "|'-,",
|
||||
"O" : ",-|'", "P" : ",','", "Q" : ",'|-", "R" : "|-,'",
|
||||
"S" : "|-|-", "T" : "|',-", "U" : ",,''", "V" : ",|-'",
|
||||
"W" : ",|'-", "X" : "|,-'", "Y" : "|,'-", "Z" : "||--",
|
||||
|
||||
# start, stop
|
||||
"(" : "'-,'", ")" : "'|,|"
|
||||
}
|
||||
|
||||
_ozN_patterns = {
|
||||
"0" : "||", "1" : "|'", "2" : "|,", "3" : "'|", "4" : "''",
|
||||
"5" : "',", "6" : ",|", "7" : ",'", "8" : ",,", "9" : ".|"
|
||||
}
|
||||
|
||||
_ozC_patterns = {
|
||||
"A" : "|||", "B" : "||'", "C" : "||,", "D" : "|'|",
|
||||
"E" : "|''", "F" : "|',", "G" : "|,|", "H" : "|,'",
|
||||
"I" : "|,,", "J" : "'||", "K" : "'|'", "L" : "'|,",
|
||||
"M" : "''|", "N" : "'''", "O" : "'',", "P" : "',|",
|
||||
"Q" : "','", "R" : "',,", "S" : ",||", "T" : ",|'",
|
||||
"U" : ",|,", "V" : ",'|", "W" : ",''", "X" : ",',",
|
||||
"Y" : ",,|", "Z" : ",,'", "a" : "|,.", "b" : "|.|",
|
||||
"c" : "|.'", "d" : "|.,", "e" : "|..", "f" : "'|.",
|
||||
"g" : "''.", "h" : "',.", "i" : "'.|", "j" : "'.'",
|
||||
"k" : "'.,", "l" : "'..", "m" : ",|.", "n" : ",'.",
|
||||
"o" : ",,.", "p" : ",.|", "q" : ",.'", "r" : ",.,",
|
||||
"s" : ",..", "t" : ".|.", "u" : ".'.", "v" : ".,.",
|
||||
"w" : "..|", "x" : "..'", "y" : "..,", "z" : "...",
|
||||
"0" : ",,,", "1" : ".||", "2" : ".|'", "3" : ".|,",
|
||||
"4" : ".'|", "5" : ".''", "6" : ".',", "7" : ".,|",
|
||||
"8" : ".,'", "9" : ".,,", " " : "||.", "#" : "|'.",
|
||||
}
|
||||
|
||||
#http://www.auspost.com.au/futurepost/
|
||||
@@ -0,0 +1,195 @@
|
||||
# (c) 2008 Jerome Alet - <alet@librelogiciel.com>
|
||||
# Licensing terms : ReportLab's license.
|
||||
|
||||
from reportlab.graphics.barcode.code39 import Standard39
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.units import cm
|
||||
from string import ascii_uppercase, digits as string_digits
|
||||
|
||||
class BaseLTOLabel(Standard39) :
|
||||
"""
|
||||
Base class for LTO labels.
|
||||
|
||||
Specification taken from "IBM LTO Ultrium Cartridge Label Specification, Revision 3"
|
||||
available on May 14th 2008 from :
|
||||
http://www-1.ibm.com/support/docview.wss?rs=543&context=STCVQ6R&q1=ssg1*&uid=ssg1S7000429&loc=en_US&cs=utf-8&lang=en+en
|
||||
"""
|
||||
LABELWIDTH = 7.9 * cm
|
||||
LABELHEIGHT = 1.7 * cm
|
||||
LABELROUND = 0.15 * cm
|
||||
CODERATIO = 2.75
|
||||
CODENOMINALWIDTH = 7.4088 * cm
|
||||
CODEBARHEIGHT = 1.11 * cm
|
||||
CODEBARWIDTH = 0.0432 * cm
|
||||
CODEGAP = CODEBARWIDTH
|
||||
CODELQUIET = 10 * CODEBARWIDTH
|
||||
CODERQUIET = 10 * CODEBARWIDTH
|
||||
def __init__(self, prefix="",
|
||||
number=None,
|
||||
subtype="1",
|
||||
border=None,
|
||||
checksum=False,
|
||||
availheight=None) :
|
||||
"""
|
||||
Initializes an LTO label.
|
||||
|
||||
prefix : Up to six characters from [A-Z][0-9]. Defaults to "".
|
||||
number : Label's number or None. Defaults to None.
|
||||
subtype : LTO subtype string , e.g. "1" for LTO1. Defaults to "1".
|
||||
border : None, or the width of the label's border. Defaults to None.
|
||||
checksum : Boolean indicates if checksum char has to be printed. Defaults to False.
|
||||
availheight : Available height on the label, or None for automatic. Defaults to None.
|
||||
"""
|
||||
self.height = max(availheight, self.CODEBARHEIGHT)
|
||||
self.border = border
|
||||
if (len(subtype) != 1) \
|
||||
or (subtype not in ascii_uppercase + string_digits) :
|
||||
raise ValueError("Invalid subtype '%s'" % subtype)
|
||||
if ((not number) and (len(prefix) > 6)) \
|
||||
or not prefix.isalnum() :
|
||||
raise ValueError("Invalid prefix '%s'" % prefix)
|
||||
label = "%sL%s" % ((prefix + str(number or 0).zfill(6 - len(prefix)))[:6],
|
||||
subtype)
|
||||
if len(label) != 8 :
|
||||
raise ValueError("Invalid set of parameters (%s, %s, %s)" \
|
||||
% (prefix, number, subtype))
|
||||
self.label = label
|
||||
Standard39.__init__(self,
|
||||
label,
|
||||
ratio=self.CODERATIO,
|
||||
barHeight=self.height,
|
||||
barWidth=self.CODEBARWIDTH,
|
||||
gap=self.CODEGAP,
|
||||
lquiet=self.CODELQUIET,
|
||||
rquiet=self.CODERQUIET,
|
||||
quiet=True,
|
||||
checksum=checksum)
|
||||
|
||||
def drawOn(self, canvas, x, y) :
|
||||
"""Draws the LTO label onto the canvas."""
|
||||
canvas.saveState()
|
||||
canvas.translate(x, y)
|
||||
if self.border :
|
||||
canvas.setLineWidth(self.border)
|
||||
canvas.roundRect(0, 0,
|
||||
self.LABELWIDTH,
|
||||
self.LABELHEIGHT,
|
||||
self.LABELROUND)
|
||||
Standard39.drawOn(self,
|
||||
canvas,
|
||||
(self.LABELWIDTH-self.CODENOMINALWIDTH)/2.0,
|
||||
self.LABELHEIGHT-self.height)
|
||||
canvas.restoreState()
|
||||
|
||||
class VerticalLTOLabel(BaseLTOLabel) :
|
||||
"""
|
||||
A class for LTO labels with rectangular blocks around the tape identifier.
|
||||
"""
|
||||
LABELFONT = ("Helvetica-Bold", 14)
|
||||
BLOCKWIDTH = 1*cm
|
||||
BLOCKHEIGHT = 0.45*cm
|
||||
LINEWIDTH = 0.0125
|
||||
NBBLOCKS = 7
|
||||
COLORSCHEME = ("red",
|
||||
"yellow",
|
||||
"lightgreen",
|
||||
"lightblue",
|
||||
"grey",
|
||||
"orangered",
|
||||
"pink",
|
||||
"darkgreen",
|
||||
"orange",
|
||||
"purple")
|
||||
|
||||
def __init__(self, *args, **kwargs) :
|
||||
"""
|
||||
Initializes the label.
|
||||
|
||||
colored : boolean to determine if blocks have to be colorized.
|
||||
"""
|
||||
if "colored" in kwargs:
|
||||
self.colored = kwargs["colored"]
|
||||
del kwargs["colored"]
|
||||
else :
|
||||
self.colored = False
|
||||
kwargs["availheight"] = self.LABELHEIGHT-self.BLOCKHEIGHT
|
||||
BaseLTOLabel.__init__(self, *args, **kwargs)
|
||||
|
||||
def drawOn(self, canvas, x, y) :
|
||||
"""Draws some blocks around the identifier's characters."""
|
||||
BaseLTOLabel.drawOn(self,
|
||||
canvas,
|
||||
x,
|
||||
y)
|
||||
canvas.saveState()
|
||||
canvas.setLineWidth(self.LINEWIDTH)
|
||||
canvas.setStrokeColorRGB(0, 0, 0)
|
||||
canvas.translate(x, y)
|
||||
xblocks = (self.LABELWIDTH-(self.NBBLOCKS*self.BLOCKWIDTH))/2.0
|
||||
for i in range(self.NBBLOCKS) :
|
||||
(font, size) = self.LABELFONT
|
||||
newfont = self.LABELFONT
|
||||
if i == (self.NBBLOCKS - 1) :
|
||||
part = self.label[i:]
|
||||
(font, size) = newfont
|
||||
size /= 2.0
|
||||
newfont = (font, size)
|
||||
else :
|
||||
part = self.label[i]
|
||||
canvas.saveState()
|
||||
canvas.translate(xblocks+(i*self.BLOCKWIDTH), 0)
|
||||
if self.colored and part.isdigit() :
|
||||
canvas.setFillColorRGB(*getattr(colors,
|
||||
self.COLORSCHEME[int(part)],
|
||||
colors.Color(1, 1, 1)).rgb())
|
||||
else:
|
||||
canvas.setFillColorRGB(1, 1, 1)
|
||||
canvas.rect(0, 0, self.BLOCKWIDTH, self.BLOCKHEIGHT, fill=True)
|
||||
canvas.translate((self.BLOCKWIDTH+canvas.stringWidth(part, *newfont))/2.0,
|
||||
(self.BLOCKHEIGHT/2.0))
|
||||
canvas.rotate(90.0)
|
||||
canvas.setFont(*newfont)
|
||||
canvas.setFillColorRGB(0, 0, 0)
|
||||
canvas.drawCentredString(0, 0, part)
|
||||
canvas.restoreState()
|
||||
canvas.restoreState()
|
||||
|
||||
def test() :
|
||||
"""Test this."""
|
||||
from reportlab.pdfgen.canvas import Canvas
|
||||
from reportlab.lib import pagesizes
|
||||
|
||||
canvas = Canvas("labels.pdf", pagesize=pagesizes.A4)
|
||||
canvas.setFont("Helvetica", 30)
|
||||
(width, height) = pagesizes.A4
|
||||
canvas.drawCentredString(width/2.0, height-4*cm, "Sample LTO labels")
|
||||
xpos = xorig = 2 * cm
|
||||
ypos = yorig = 2 * cm
|
||||
colwidth = 10 * cm
|
||||
lineheight = 3.9 * cm
|
||||
count = 1234
|
||||
BaseLTOLabel("RL", count, "3").drawOn(canvas, xpos, ypos)
|
||||
ypos += lineheight
|
||||
count += 1
|
||||
BaseLTOLabel("RL", count, "3",
|
||||
border=0.0125).drawOn(canvas, xpos, ypos)
|
||||
ypos += lineheight
|
||||
count += 1
|
||||
VerticalLTOLabel("RL", count, "3").drawOn(canvas, xpos, ypos)
|
||||
ypos += lineheight
|
||||
count += 1
|
||||
VerticalLTOLabel("RL", count, "3",
|
||||
border=0.0125).drawOn(canvas, xpos, ypos)
|
||||
ypos += lineheight
|
||||
count += 1
|
||||
VerticalLTOLabel("RL", count, "3",
|
||||
colored=True).drawOn(canvas, xpos, ypos)
|
||||
ypos += lineheight
|
||||
count += 1
|
||||
VerticalLTOLabel("RL", count, "3",
|
||||
border=0.0125, colored=True).drawOn(canvas, xpos, ypos)
|
||||
canvas.showPage()
|
||||
canvas.save()
|
||||
|
||||
if __name__ == "__main__" :
|
||||
test()
|
||||
@@ -0,0 +1,197 @@
|
||||
#
|
||||
# ReportLab QRCode widget
|
||||
#
|
||||
# Ported from the Javascript library QRCode for Javascript by Sam Curren
|
||||
#
|
||||
# URL: http://www.d-project.com/
|
||||
# http://d-project.googlecode.com/svn/trunk/misc/qrcode/js/qrcode.js
|
||||
# qrcode.js is copyright (c) 2009 Kazuhiko Arase
|
||||
#
|
||||
# Original ReportLab module by German M. Bravo
|
||||
#
|
||||
# modified and improved by Anders Hammarquist <iko@openend.se>
|
||||
# and used with permission under the ReportLab License
|
||||
#
|
||||
# The word "QR Code" is registered trademark of
|
||||
# DENSO WAVE INCORPORATED
|
||||
# http://www.denso-wave.com/qrcode/faqpatent-e.html
|
||||
|
||||
__all__ = ('QrCodeWidget')
|
||||
|
||||
import itertools
|
||||
|
||||
from reportlab.platypus.flowables import Flowable
|
||||
from reportlab.graphics.shapes import Group, Rect
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.validators import isNumber, isNumberOrNone, isColor, Validator
|
||||
from reportlab.lib.attrmap import AttrMap, AttrMapValue
|
||||
from reportlab.graphics.widgetbase import Widget
|
||||
from reportlab.lib.units import mm
|
||||
from reportlab.lib.utils import asUnicodeEx, isUnicode
|
||||
from reportlab.graphics.barcode import qrencoder
|
||||
|
||||
class isLevel(Validator):
|
||||
def test(self, x):
|
||||
return x in ['L', 'M', 'Q', 'H']
|
||||
isLevel = isLevel()
|
||||
|
||||
class isUnicodeOrQRList(Validator):
|
||||
def _test(self, x):
|
||||
if isUnicode(x):
|
||||
return True
|
||||
if all(isinstance(v, qrencoder.QR) for v in x):
|
||||
return True
|
||||
return False
|
||||
|
||||
def test(self, x):
|
||||
return self._test(x) or self.normalizeTest(x)
|
||||
|
||||
def normalize(self, x):
|
||||
if self._test(x):
|
||||
return x
|
||||
try:
|
||||
return asUnicodeEx(x)
|
||||
except UnicodeError:
|
||||
raise ValueError("Can't convert to unicode: %r" % x)
|
||||
isUnicodeOrQRList = isUnicodeOrQRList()
|
||||
|
||||
class SRect(Rect):
|
||||
def __init__(self, x, y, width, height, fillColor=colors.black):
|
||||
Rect.__init__(self, x, y, width, height, fillColor=fillColor,
|
||||
strokeColor=None, strokeWidth=0)
|
||||
|
||||
class QrCodeWidget(Widget):
|
||||
codeName = "QR"
|
||||
_attrMap = AttrMap(
|
||||
BASE = Widget,
|
||||
value = AttrMapValue(isUnicodeOrQRList, desc='QRCode data'),
|
||||
x = AttrMapValue(isNumber, desc='x-coord'),
|
||||
y = AttrMapValue(isNumber, desc='y-coord'),
|
||||
barFillColor = AttrMapValue(isColor, desc='bar color'),
|
||||
barWidth = AttrMapValue(isNumber, desc='Width of bars.'), # maybe should be named just width?
|
||||
barHeight = AttrMapValue(isNumber, desc='Height of bars.'), # maybe should be named just height?
|
||||
barBorder = AttrMapValue(isNumber, desc='Width of QR border.'), # maybe should be named qrBorder?
|
||||
barLevel = AttrMapValue(isLevel, desc='QR Code level.'), # maybe should be named qrLevel
|
||||
qrVersion = AttrMapValue(isNumberOrNone, desc='QR Code version. None for auto'),
|
||||
# Below are ignored, they make no sense
|
||||
barStrokeWidth = AttrMapValue(isNumber, desc='Width of bar borders.'),
|
||||
barStrokeColor = AttrMapValue(isColor, desc='Color of bar borders.'),
|
||||
)
|
||||
x = 0
|
||||
y = 0
|
||||
barFillColor = colors.black
|
||||
barStrokeColor = None
|
||||
barStrokeWidth = 0
|
||||
barHeight = 32*mm
|
||||
barWidth = 32*mm
|
||||
barBorder = 4
|
||||
barLevel = 'L'
|
||||
qrVersion = None
|
||||
value = None
|
||||
|
||||
def __init__(self, value='Hello World', **kw):
|
||||
self.value = isUnicodeOrQRList.normalize(value)
|
||||
for k, v in kw.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
ec_level = getattr(qrencoder.QRErrorCorrectLevel, self.barLevel)
|
||||
|
||||
self.__dict__['qr'] = qrencoder.QRCode(self.qrVersion, ec_level)
|
||||
|
||||
if isUnicode(self.value):
|
||||
self.addData(self.value)
|
||||
elif self.value:
|
||||
for v in self.value:
|
||||
self.addData(v)
|
||||
|
||||
def addData(self, value):
|
||||
self.qr.addData(value)
|
||||
|
||||
def draw(self):
|
||||
self.qr.make()
|
||||
|
||||
g = Group()
|
||||
|
||||
color = self.barFillColor
|
||||
border = self.barBorder
|
||||
width = self.barWidth
|
||||
height = self.barHeight
|
||||
x = self.x
|
||||
y = self.y
|
||||
|
||||
g.add(SRect(x, y, width, height, fillColor=None))
|
||||
|
||||
moduleCount = self.qr.getModuleCount()
|
||||
minwh = float(min(width, height))
|
||||
boxsize = minwh / (moduleCount + border * 2.0)
|
||||
offsetX = x + (width - minwh) / 2.0
|
||||
offsetY = y + (minwh - height) / 2.0
|
||||
|
||||
for r, row in enumerate(self.qr.modules):
|
||||
row = map(bool, row)
|
||||
c = 0
|
||||
for t, tt in itertools.groupby(row):
|
||||
isDark = t
|
||||
count = len(list(tt))
|
||||
if isDark:
|
||||
x = (c + border) * boxsize
|
||||
y = (r + border + 1) * boxsize
|
||||
s = SRect(offsetX + x, offsetY + height - y, count * boxsize, boxsize,
|
||||
fillColor=color)
|
||||
g.add(s)
|
||||
c += count
|
||||
|
||||
return g
|
||||
|
||||
|
||||
# Flowable version
|
||||
|
||||
class QrCode(Flowable):
|
||||
height = 32*mm
|
||||
width = 32*mm
|
||||
qrBorder = 4
|
||||
qrLevel = 'L'
|
||||
qrVersion = None
|
||||
value = None
|
||||
|
||||
def __init__(self, value=None, **kw):
|
||||
self.value = isUnicodeOrQRList.normalize(value)
|
||||
|
||||
for k, v in kw.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
ec_level = getattr(qrencoder.QRErrorCorrectLevel, self.qrLevel)
|
||||
|
||||
self.qr = qrencoder.QRCode(self.qrVersion, ec_level)
|
||||
|
||||
if isUnicode(self.value):
|
||||
self.addData(self.value)
|
||||
elif self.value:
|
||||
for v in self.value:
|
||||
self.addData(v)
|
||||
|
||||
def addData(self, value):
|
||||
self.qr.addData(value)
|
||||
|
||||
def draw(self):
|
||||
self.qr.make()
|
||||
|
||||
moduleCount = self.qr.getModuleCount()
|
||||
border = self.qrBorder
|
||||
xsize = self.width / (moduleCount + border * 2.0)
|
||||
ysize = self.height / (moduleCount + border * 2.0)
|
||||
|
||||
for r, row in enumerate(self.qr.modules):
|
||||
row = map(bool, row)
|
||||
c = 0
|
||||
for t, tt in itertools.groupby(row):
|
||||
isDark = t
|
||||
count = len(list(tt))
|
||||
if isDark:
|
||||
x = (c + border) * xsize
|
||||
y = self.height - (r + border + 1) * ysize
|
||||
self.rect(x, y, count * xsize, ysize * 1.05)
|
||||
c += count
|
||||
|
||||
def rect(self, x, y, w, h):
|
||||
self.canv.rect(x, y, w, h, stroke=0, fill=1)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,280 @@
|
||||
#!/usr/pkg/bin/python
|
||||
|
||||
import sys, time
|
||||
|
||||
from reportlab import Version as __RL_Version__
|
||||
from reportlab.graphics.barcode.common import *
|
||||
from reportlab.graphics.barcode.code39 import *
|
||||
from reportlab.graphics.barcode.code93 import *
|
||||
from reportlab.graphics.barcode.code128 import *
|
||||
from reportlab.graphics.barcode.usps import *
|
||||
from reportlab.graphics.barcode.usps4s import USPS_4State
|
||||
from reportlab.graphics.barcode.qr import QrCodeWidget
|
||||
from reportlab.graphics.barcode.dmtx import DataMatrixWidget, pylibdmtx
|
||||
|
||||
from reportlab.platypus import Spacer, SimpleDocTemplate, PageBreak
|
||||
from reportlab.lib.units import inch
|
||||
from reportlab.lib import colors
|
||||
|
||||
from reportlab.lib.styles import getSampleStyleSheet
|
||||
from reportlab.platypus.paragraph import Paragraph
|
||||
from reportlab.platypus.flowables import XBox, KeepTogether
|
||||
from reportlab.graphics.shapes import Drawing, Rect, Line
|
||||
|
||||
from reportlab.graphics.barcode import getCodeNames, createBarcodeDrawing, createBarcodeImageInMemory
|
||||
|
||||
def run():
|
||||
styles = getSampleStyleSheet()
|
||||
styleN = styles['Normal']
|
||||
styleH = styles['Heading1']
|
||||
story = []
|
||||
storyAdd = story.append
|
||||
|
||||
#for codeNames in code
|
||||
storyAdd(Paragraph('I2of5', styleN))
|
||||
storyAdd(I2of5('05400141288766', barWidth = inch*0.02, checksum=0))
|
||||
storyAdd(I2of5('0001234567890', barWidth = inch*0.02, checksum=1))
|
||||
storyAdd(I2of5('00012345678905', barWidth = inch*0.02, checksum=0))
|
||||
storyAdd(I2of5('0001234567890', barWidth = inch*0.02, checksum=1, bearerBox = True))
|
||||
|
||||
|
||||
storyAdd(Paragraph('MSI', styleN))
|
||||
storyAdd(MSI(1234))
|
||||
|
||||
storyAdd(Paragraph('Codabar', styleN))
|
||||
storyAdd(Codabar("A012345B", barWidth = inch*0.02))
|
||||
|
||||
storyAdd(Paragraph('Code 11', styleN))
|
||||
storyAdd(Code11("01234545634563"))
|
||||
|
||||
storyAdd(Paragraph('Code 39', styleN))
|
||||
storyAdd(Standard39("A012345B%R"))
|
||||
|
||||
storyAdd(Paragraph('Extended Code 39', styleN))
|
||||
storyAdd(Extended39("A012345B}"))
|
||||
|
||||
storyAdd(Paragraph('Code93', styleN))
|
||||
storyAdd(Standard93("CODE 93"))
|
||||
|
||||
storyAdd(Paragraph('Extended Code93', styleN))
|
||||
storyAdd(Extended93("L@@K! Code 93 :-)")) #, barWidth=0.005 * inch))
|
||||
|
||||
storyAdd(Paragraph('Code 128', styleN))
|
||||
storyAdd(Code128("AB-12345678"))
|
||||
|
||||
storyAdd(Paragraph('Code 128 Auto', styleN))
|
||||
storyAdd(Code128Auto("AB-12345678"))
|
||||
|
||||
storyAdd(Paragraph('USPS FIM', styleN))
|
||||
storyAdd(FIM("A"))
|
||||
|
||||
storyAdd(Paragraph('USPS POSTNET', styleN))
|
||||
storyAdd(POSTNET('78247-1043'))
|
||||
|
||||
storyAdd(Paragraph('USPS 4 State', styleN))
|
||||
storyAdd(USPS_4State('01234567094987654321','01234567891'))
|
||||
|
||||
from reportlab.graphics.barcode import createBarcodeDrawing
|
||||
|
||||
storyAdd(Paragraph('EAN13', styleN))
|
||||
storyAdd(createBarcodeDrawing('EAN13', value='123456789012'))
|
||||
|
||||
storyAdd(Paragraph('EAN13 quiet=False', styleN))
|
||||
storyAdd(createBarcodeDrawing('EAN13', value='123456789012', quiet=False))
|
||||
|
||||
storyAdd(Paragraph('EAN8', styleN))
|
||||
storyAdd(createBarcodeDrawing('EAN8', value='1234567'))
|
||||
|
||||
storyAdd(PageBreak())
|
||||
|
||||
storyAdd(Paragraph('EAN5 price=True', styleN))
|
||||
storyAdd(createBarcodeDrawing('EAN5', value='11299', price=True))
|
||||
|
||||
storyAdd(Paragraph('EAN5 price=True quiet=False', styleN))
|
||||
storyAdd(createBarcodeDrawing('EAN5', value='11299', price=True, quiet=False))
|
||||
|
||||
storyAdd(Paragraph('EAN5 price=False', styleN))
|
||||
storyAdd(createBarcodeDrawing('EAN5', value='11299', price=False))
|
||||
|
||||
storyAdd(Paragraph('ISBN alone', styleN))
|
||||
storyAdd(createBarcodeDrawing('ISBN', value='9781565924796'))
|
||||
|
||||
storyAdd(Paragraph('ISBN with ean5 price', styleN))
|
||||
storyAdd(createBarcodeDrawing('ISBN', value='9781565924796',price='01299'))
|
||||
|
||||
storyAdd(Paragraph('ISBN with ean5 price, quiet=False', styleN))
|
||||
storyAdd(createBarcodeDrawing('ISBN', value='9781565924796',price='01299',quiet=False))
|
||||
|
||||
storyAdd(Paragraph('UPCA', styleN))
|
||||
storyAdd(createBarcodeDrawing('UPCA', value='03600029145'))
|
||||
|
||||
storyAdd(Paragraph('USPS_4State', styleN))
|
||||
storyAdd(createBarcodeDrawing('USPS_4State', value='01234567094987654321',routing='01234567891'))
|
||||
|
||||
storyAdd(Paragraph('QR', styleN))
|
||||
storyAdd(createBarcodeDrawing('QR', value='01234567094987654321'))
|
||||
|
||||
storyAdd(Paragraph('QR', styleN))
|
||||
storyAdd(createBarcodeDrawing('QR', value='01234567094987654321',x=30,y=50))
|
||||
|
||||
def addCross(d,x,y,w=5,h=5, strokeColor='black', strokeWidth=0.5):
|
||||
w *= 0.5
|
||||
h *= 0.5
|
||||
d.add(Line(x-w,y,x+w,y,strokeWidth=0.5,strokeColor=colors.blue))
|
||||
d.add(Line(x, y-h, x, y+h,strokeWidth=0.5,strokeColor=colors.blue))
|
||||
storyAdd(Paragraph('QR in drawing at (0,0)', styleN))
|
||||
d = Drawing(100,100)
|
||||
d.add(Rect(0,0,100,100,strokeWidth=1,strokeColor=colors.red,fillColor=None))
|
||||
d.add(QrCodeWidget(value='01234567094987654321'))
|
||||
storyAdd(d)
|
||||
|
||||
storyAdd(Paragraph('QR in drawing at (10,10)', styleN))
|
||||
d = Drawing(100,100)
|
||||
d.add(Rect(0,0,100,100,strokeWidth=1,strokeColor=colors.red,fillColor=None))
|
||||
addCross(d,10,10)
|
||||
d.add(QrCodeWidget(value='01234567094987654321',x=10,y=10))
|
||||
storyAdd(d)
|
||||
|
||||
storyAdd(Paragraph('Label Size', styleN))
|
||||
storyAdd(XBox((2.0 + 5.0/8.0)*inch, 1 * inch, '1x2-5/8"'))
|
||||
|
||||
storyAdd(Paragraph('Label Size', styleN))
|
||||
storyAdd(XBox((1.75)*inch, .5 * inch, '1/2x1-3/4"'))
|
||||
|
||||
if pylibdmtx:
|
||||
storyAdd(PageBreak())
|
||||
storyAdd(Paragraph('DataMatrix in drawing at (10,10)', styleN))
|
||||
d = Drawing(100,100)
|
||||
d.add(Rect(0,0,100,100,strokeWidth=1,strokeColor=colors.red,fillColor=None))
|
||||
addCross(d,10,10)
|
||||
d.add(DataMatrixWidget(value='1234567890',x=10,y=10))
|
||||
storyAdd(d)
|
||||
storyAdd(Paragraph('DataMatrix in drawing at (10,10)', styleN))
|
||||
d = Drawing(100,100)
|
||||
d.add(Rect(0,0,100,100,strokeWidth=1,strokeColor=colors.red,fillColor=None))
|
||||
addCross(d,10,10)
|
||||
d.add(DataMatrixWidget(value='1234567890',x=10,y=10,color='black',bgColor='lime'))
|
||||
storyAdd(d)
|
||||
|
||||
storyAdd(Paragraph('DataMatrix in drawing at (90,90) anchor=ne', styleN))
|
||||
d = Drawing(100,100)
|
||||
d.add(Rect(0,0,100,100,strokeWidth=1,strokeColor=colors.red,fillColor=None))
|
||||
addCross(d,90,90)
|
||||
d.add(DataMatrixWidget(value='1234567890',x=90,y=90,color='darkblue',bgColor='yellow', anchor='ne'))
|
||||
storyAdd(d)
|
||||
|
||||
|
||||
SimpleDocTemplate('out.pdf').build(story)
|
||||
print('saved out.pdf')
|
||||
|
||||
def fullTest(fileName="test_full.pdf"):
|
||||
"""Creates large-ish test document with a variety of parameters"""
|
||||
|
||||
story = []
|
||||
|
||||
styles = getSampleStyleSheet()
|
||||
styleN = styles['Normal']
|
||||
styleH = styles['Heading1']
|
||||
styleH2 = styles['Heading2']
|
||||
story = []
|
||||
|
||||
story.append(Paragraph('ReportLab %s Barcode Test Suite - full output' % __RL_Version__,styleH))
|
||||
story.append(Paragraph('Generated at %s' % time.ctime(time.time()), styleN))
|
||||
|
||||
story.append(Paragraph('About this document', styleH2))
|
||||
story.append(Paragraph('History and Status', styleH2))
|
||||
|
||||
story.append(Paragraph("""
|
||||
This is the test suite and docoumentation for the ReportLab open source barcode API.
|
||||
""", styleN))
|
||||
|
||||
story.append(Paragraph("""
|
||||
Several years ago Ty Sarna contributed a barcode module to the ReportLab community.
|
||||
Several of the codes were used by him in hiw work and to the best of our knowledge
|
||||
this was correct. These were written as flowable objects and were available in PDFs,
|
||||
but not in our graphics framework. However, we had no knowledge of barcodes ourselves
|
||||
and did not advertise or extend the package.
|
||||
""", styleN))
|
||||
|
||||
story.append(Paragraph("""
|
||||
We "wrapped" the barcodes to be usable within our graphics framework; they are now available
|
||||
as Drawing objects which can be rendered to EPS files or bitmaps. For the last 2 years this
|
||||
has been available in our Diagra and Report Markup Language products. However, we did not
|
||||
charge separately and use was on an "as is" basis.
|
||||
""", styleN))
|
||||
|
||||
story.append(Paragraph("""
|
||||
A major licensee of our technology has kindly agreed to part-fund proper productisation
|
||||
of this code on an open source basis in Q1 2006. This has involved addition of EAN codes
|
||||
as well as a proper testing program. Henceforth we intend to publicise the code more widely,
|
||||
gather feedback, accept contributions of code and treat it as "supported".
|
||||
""", styleN))
|
||||
|
||||
story.append(Paragraph("""
|
||||
This involved making available both downloads and testing resources. This PDF document
|
||||
is the output of the current test suite. It contains codes you can scan (if you use a nice sharp
|
||||
laser printer!), and will be extended over coming weeks to include usage examples and notes on
|
||||
each barcode and how widely tested they are. This is being done through documentation strings in
|
||||
the barcode objects themselves so should always be up to date.
|
||||
""", styleN))
|
||||
|
||||
story.append(Paragraph('Usage examples', styleH2))
|
||||
story.append(Paragraph("""
|
||||
To be completed
|
||||
""", styleN))
|
||||
|
||||
story.append(Paragraph('The codes', styleH2))
|
||||
story.append(Paragraph("""
|
||||
Below we show a scannable code from each barcode, with and without human-readable text.
|
||||
These are magnified about 2x from the natural size done by the original author to aid
|
||||
inspection. This will be expanded to include several test cases per code, and to add
|
||||
explanations of checksums. Be aware that (a) if you enter numeric codes which are too
|
||||
short they may be prefixed for you (e.g. "123" for an 8-digit code becomes "00000123"),
|
||||
and that the scanned results and readable text will generally include extra checksums
|
||||
at the end.
|
||||
""", styleN))
|
||||
|
||||
codeNames = getCodeNames()
|
||||
from reportlab.lib.utils import flatten
|
||||
width = [float(x[8:]) for x in sys.argv if x.startswith('--width=')]
|
||||
height = [float(x[9:]) for x in sys.argv if x.startswith('--height=')]
|
||||
isoScale = [int(x[11:]) for x in sys.argv if x.startswith('--isoscale=')]
|
||||
options = {}
|
||||
if width: options['width'] = width[0]
|
||||
if height: options['height'] = height[0]
|
||||
if isoScale: options['isoScale'] = isoScale[0]
|
||||
scales = [x[8:].split(',') for x in sys.argv if x.startswith('--scale=')]
|
||||
scales = list(map(float,scales and flatten(scales) or [1]))
|
||||
scales = list(map(float,scales and flatten(scales) or [1]))
|
||||
for scale in scales:
|
||||
story.append(PageBreak())
|
||||
story.append(Paragraph('Scale = %.1f'%scale, styleH2))
|
||||
story.append(Spacer(36, 12))
|
||||
for codeName in codeNames:
|
||||
s = [Paragraph('Code: ' + codeName, styleH2)]
|
||||
for hr in (0,1):
|
||||
s.append(Spacer(36, 12))
|
||||
dr = createBarcodeDrawing(codeName, humanReadable=hr,**options)
|
||||
dr.renderScale = scale
|
||||
s.append(dr)
|
||||
s.append(Spacer(36, 12))
|
||||
s.append(Paragraph('Barcode should say: ' + dr._bc.value, styleN))
|
||||
story.append(KeepTogether(s))
|
||||
|
||||
SimpleDocTemplate(fileName).build(story)
|
||||
print('created', fileName)
|
||||
|
||||
if __name__=='__main__':
|
||||
run()
|
||||
fullTest()
|
||||
def createSample(name,memory):
|
||||
f = open(name,'wb')
|
||||
f.write(memory)
|
||||
f.close()
|
||||
createSample('test_cbcim.png',createBarcodeImageInMemory('EAN13', value='123456789012'))
|
||||
createSample('test_cbcim.gif',createBarcodeImageInMemory('EAN8', value='1234567', format='gif'))
|
||||
createSample('test_cbcim.pdf',createBarcodeImageInMemory('UPCA', value='03600029145',format='pdf', barHeight=40))
|
||||
createSample('test_cbcim.tiff',createBarcodeImageInMemory('USPS_4State', value='01234567094987654321',routing='01234567891',format='tiff'))
|
||||
createSample('test_cbcim-1.pdf',createBarcodeImageInMemory('QR',
|
||||
value='This is the end my only friend the end at the end of the Universe.',format='pdf'))
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
#
|
||||
# Copyright (c) 1996-2000 Tyler C. Sarna <tsarna@sarna.org>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by Tyler C. Sarna.
|
||||
# 4. Neither the name of the author nor the names of contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
from reportlab.lib.units import inch
|
||||
from reportlab.graphics.barcode.common import Barcode
|
||||
from string import digits as string_digits, whitespace as string_whitespace
|
||||
from reportlab.lib.utils import asNative
|
||||
|
||||
_fim_patterns = {
|
||||
'A' : "|| | ||",
|
||||
'B' : "| || || |",
|
||||
'C' : "|| | | ||",
|
||||
'D' : "||| | |||",
|
||||
# XXX There is an E.
|
||||
# The below has been seen, but dunno if it is E or not:
|
||||
# 'E' : '|||| ||||'
|
||||
}
|
||||
|
||||
_postnet_patterns = {
|
||||
'1' : "...||", '2' : "..|.|", '3' : "..||.", '4' : ".|..|",
|
||||
'5' : ".|.|.", '6' : ".||..", '7' : "|...|", '8' : "|..|.",
|
||||
'9' : "|.|..", '0' : "||...", 'S' : "|",
|
||||
}
|
||||
|
||||
class FIM(Barcode):
|
||||
"""
|
||||
FIM (Facing ID Marks) encode only one letter.
|
||||
There are currently four defined:
|
||||
|
||||
A Courtesy reply mail with pre-printed POSTNET
|
||||
B Business reply mail without pre-printed POSTNET
|
||||
C Business reply mail with pre-printed POSTNET
|
||||
D OCR Readable mail without pre-printed POSTNET
|
||||
|
||||
Options that may be passed to constructor:
|
||||
|
||||
value (single character string from the set A - D. required.):
|
||||
The value to encode.
|
||||
|
||||
quiet (bool, default 0):
|
||||
Whether to include quiet zones in the symbol.
|
||||
|
||||
The following may also be passed, but doing so will generate nonstandard
|
||||
symbols which should not be used. This is mainly documented here to
|
||||
show the defaults:
|
||||
|
||||
barHeight (float, default 5/8 inch):
|
||||
Height of the code. This might legitimately be overriden to make
|
||||
a taller symbol that will 'bleed' off the edge of the paper,
|
||||
leaving 5/8 inch remaining.
|
||||
|
||||
lquiet (float, default 1/4 inch):
|
||||
Quiet zone size to left of code, if quiet is true.
|
||||
Default is the greater of .25 inch, or .15 times the symbol's
|
||||
length.
|
||||
|
||||
rquiet (float, default 15/32 inch):
|
||||
Quiet zone size to right left of code, if quiet is true.
|
||||
|
||||
Sources of information on FIM:
|
||||
|
||||
USPS Publication 25, A Guide to Business Mail Preparation
|
||||
http://new.usps.com/cpim/ftp/pubs/pub25.pdf
|
||||
"""
|
||||
barWidth = inch * (1.0/32.0)
|
||||
spaceWidth = inch * (1.0/16.0)
|
||||
barHeight = inch * (5.0/8.0)
|
||||
rquiet = inch * (0.25)
|
||||
lquiet = inch * (15.0/32.0)
|
||||
quiet = 0
|
||||
def __init__(self, value='', **args):
|
||||
value = str(value) if isinstance(value,int) else asNative(value)
|
||||
for k, v in args.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
Barcode.__init__(self, value)
|
||||
|
||||
def validate(self):
|
||||
self.valid = 1
|
||||
self.validated = ''
|
||||
for c in self.value:
|
||||
if c in string_whitespace:
|
||||
continue
|
||||
elif c in "abcdABCD":
|
||||
self.validated = self.validated + c.upper()
|
||||
else:
|
||||
self.valid = 0
|
||||
|
||||
if len(self.validated) != 1:
|
||||
raise ValueError("Input must be exactly one character")
|
||||
|
||||
return self.validated
|
||||
|
||||
def decompose(self):
|
||||
self.decomposed = ''
|
||||
for c in self.encoded:
|
||||
self.decomposed = self.decomposed + _fim_patterns[c]
|
||||
|
||||
return self.decomposed
|
||||
|
||||
def computeSize(self):
|
||||
self._width = (len(self.decomposed) - 1) * self.spaceWidth + self.barWidth
|
||||
if self.quiet:
|
||||
self._width += self.lquiet + self.rquiet
|
||||
self._height = self.barHeight
|
||||
|
||||
def draw(self):
|
||||
self._calculate()
|
||||
left = self.quiet and self.lquiet or 0
|
||||
for c in self.decomposed:
|
||||
if c == '|':
|
||||
self.rect(left, 0.0, self.barWidth, self.barHeight)
|
||||
left += self.spaceWidth
|
||||
self.drawHumanReadable()
|
||||
|
||||
def _humanText(self):
|
||||
return self.value
|
||||
|
||||
class POSTNET(Barcode):
|
||||
"""
|
||||
POSTNET is used in the US to encode "zip codes" (postal codes) on
|
||||
mail. It can encode 5, 9, or 11 digit codes. I've read that it's
|
||||
pointless to do 5 digits, since USPS will just have to re-print
|
||||
them with 9 or 11 digits.
|
||||
|
||||
Sources of information on POSTNET:
|
||||
|
||||
USPS Publication 25, A Guide to Business Mail Preparation
|
||||
http://new.usps.com/cpim/ftp/pubs/pub25.pdf
|
||||
"""
|
||||
quiet = 0
|
||||
shortHeight = inch * 0.050
|
||||
barHeight = inch * 0.125
|
||||
barWidth = inch * 0.018
|
||||
spaceWidth = inch * 0.0275
|
||||
def __init__(self, value='', **args):
|
||||
value = str(value) if isinstance(value,int) else asNative(value)
|
||||
for k, v in args.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
Barcode.__init__(self, value)
|
||||
|
||||
def validate(self):
|
||||
self.validated = ''
|
||||
self.valid = 1
|
||||
count = 0
|
||||
for c in self.value:
|
||||
if c in (string_whitespace + '-'):
|
||||
pass
|
||||
elif c in string_digits:
|
||||
count = count + 1
|
||||
if count == 6:
|
||||
self.validated = self.validated + '-'
|
||||
self.validated = self.validated + c
|
||||
else:
|
||||
self.valid = 0
|
||||
|
||||
if len(self.validated) not in [5, 10, 12]:
|
||||
self.valid = 0
|
||||
|
||||
return self.validated
|
||||
|
||||
def encode(self):
|
||||
self.encoded = "S"
|
||||
check = 0
|
||||
for c in self.validated:
|
||||
if c in string_digits:
|
||||
self.encoded = self.encoded + c
|
||||
check = check + int(c)
|
||||
elif c == '-':
|
||||
pass
|
||||
else:
|
||||
raise ValueError("Invalid character in input")
|
||||
check = (10 - check) % 10
|
||||
self.encoded = self.encoded + repr(check) + 'S'
|
||||
return self.encoded
|
||||
|
||||
def decompose(self):
|
||||
self.decomposed = ''
|
||||
for c in self.encoded:
|
||||
self.decomposed = self.decomposed + _postnet_patterns[c]
|
||||
return self.decomposed
|
||||
|
||||
def computeSize(self):
|
||||
self._width = len(self.decomposed) * self.barWidth + (len(self.decomposed) - 1) * self.spaceWidth
|
||||
self._height = self.barHeight
|
||||
|
||||
def draw(self):
|
||||
self._calculate()
|
||||
sdown = self.barHeight - self.shortHeight
|
||||
left = 0
|
||||
|
||||
for c in self.decomposed:
|
||||
if c == '.':
|
||||
h = self.shortHeight
|
||||
else:
|
||||
h = self.barHeight
|
||||
self.rect(left, 0.0, self.barWidth, h)
|
||||
left = left + self.barWidth + self.spaceWidth
|
||||
self.drawHumanReadable()
|
||||
|
||||
def _humanText(self):
|
||||
return self.encoded[1:-1]
|
||||
@@ -0,0 +1,465 @@
|
||||
#copyright ReportLab Inc. 2000-2016
|
||||
#see license.txt for license details
|
||||
from __future__ import print_function
|
||||
__version__='3.3.0'
|
||||
__all__ = ('USPS_4State',)
|
||||
|
||||
from reportlab.graphics.barcode.common import Barcode
|
||||
from reportlab.lib.utils import asNative
|
||||
|
||||
def nhex(i):
|
||||
'normalized hex'
|
||||
r = hex(i)
|
||||
r = r[:2]+r[2:].lower()
|
||||
if r.endswith('l'): r = r[:-1]
|
||||
return r
|
||||
|
||||
class USPS_4State(Barcode):
|
||||
''' USPS 4-State OneView (TM) barcode. All info from USPS-B-3200A
|
||||
'''
|
||||
_widthSize = 1
|
||||
_heightSize = 1
|
||||
_fontSize = 11
|
||||
_humanReadable = 0
|
||||
if True:
|
||||
tops = dict(
|
||||
F = (0.0625,0.0825),
|
||||
T = (0.0195,0.0285),
|
||||
A = (0.0625,0.0825),
|
||||
D = (0.0195,0.0285),
|
||||
)
|
||||
bottoms = dict(
|
||||
F = (-0.0625,-0.0825),
|
||||
T = (-0.0195,-0.0285),
|
||||
D = (-0.0625,-0.0825),
|
||||
A = (-0.0195,-0.0285),
|
||||
)
|
||||
dimensions = dict(
|
||||
width = (0.015, 0.025),
|
||||
pitch = (0.0416, 0.050),
|
||||
hcz = (0.125,0.125),
|
||||
vcz = (0.028,0.028),
|
||||
)
|
||||
else:
|
||||
tops = dict(
|
||||
F = (0.067,0.115),
|
||||
T = (0.021,0.040),
|
||||
A = (0.067,0.115),
|
||||
D = (0.021,0.040),
|
||||
)
|
||||
bottoms = dict(
|
||||
F = (-0.067,-0.115),
|
||||
D = (-0.067,-0.115),
|
||||
T = (-0.021,-0.040),
|
||||
A = (-0.021,-0.040),
|
||||
)
|
||||
dimensions = dict(
|
||||
width = (0.015, 0.025),
|
||||
pitch = (0.0416,0.050),
|
||||
hcz = (0.125,0.125),
|
||||
vcz = (0.040,0.040),
|
||||
)
|
||||
|
||||
def __init__(self,value='01234567094987654321',routing='',**kwd):
|
||||
self._init()
|
||||
value = str(value) if isinstance(value,int) else asNative(value)
|
||||
if not routing:
|
||||
#legal values for combined tracking + routing
|
||||
if len(value) in (20,25,29,31):
|
||||
value, routing = value[:20], value[20:]
|
||||
else:
|
||||
raise ValueError('value+routing length must be 20, 25, 29 or 31 digits not %d' % len(value))
|
||||
elif len(routing) not in (5,9,11):
|
||||
raise ValueError('routing length must be 5, 9 or 11 digits not %d' % len(routing))
|
||||
self._tracking = value
|
||||
self._routing = routing
|
||||
self._setKeywords(**kwd)
|
||||
|
||||
def _init(self):
|
||||
self._bvalue = None
|
||||
self._codewords = None
|
||||
self._characters = None
|
||||
self._barcodes = None
|
||||
|
||||
def scale(kind,D,s):
|
||||
V = D[kind]
|
||||
return 72*(V[0]*(1-s)+s*V[1])
|
||||
scale = staticmethod(scale)
|
||||
|
||||
def tracking(self,tracking):
|
||||
self._init()
|
||||
self._tracking = tracking
|
||||
tracking = property(lambda self: self._tracking,tracking)
|
||||
|
||||
def routing(self,routing):
|
||||
self._init()
|
||||
self._routing = routing
|
||||
routing = property(lambda self: self._routing,routing)
|
||||
|
||||
def widthSize(self,value):
|
||||
self._sized = None
|
||||
self._widthSize = min(max(0,value),1)
|
||||
widthSize = property(lambda self: self._widthSize,widthSize)
|
||||
|
||||
def heightSize(self,value):
|
||||
self._sized = None
|
||||
self._heightSize = value
|
||||
heightSize = property(lambda self: self._heightSize,heightSize)
|
||||
|
||||
def fontSize(self,value):
|
||||
self._sized = None
|
||||
self._fontSize = value
|
||||
fontSize = property(lambda self: self._fontSize,fontSize)
|
||||
|
||||
def humanReadable(self,value):
|
||||
self._sized = None
|
||||
self._humanReadable = value
|
||||
humanReadable = property(lambda self: self._humanReadable,humanReadable)
|
||||
|
||||
def binary(self):
|
||||
'''convert the 4 state string values to binary
|
||||
>>> print(nhex(USPS_4State('01234567094987654321','').binary))
|
||||
0x1122103b5c2004b1
|
||||
>>> print(nhex(USPS_4State('01234567094987654321','01234').binary))
|
||||
0xd138a87bab5cf3804b1
|
||||
>>> print(nhex(USPS_4State('01234567094987654321','012345678').binary))
|
||||
0x202bdc097711204d21804b1
|
||||
>>> print(nhex(USPS_4State('01234567094987654321','01234567891').binary))
|
||||
0x16907b2a24abc16a2e5c004b1
|
||||
'''
|
||||
value = self._bvalue
|
||||
if not value:
|
||||
routing = self.routing
|
||||
n = len(routing)
|
||||
try:
|
||||
if n==0:
|
||||
value = 0
|
||||
elif n==5:
|
||||
value = int(routing)+1
|
||||
elif n==9:
|
||||
value = int(routing)+100001
|
||||
elif n==11:
|
||||
value = int(routing)+1000100001
|
||||
else:
|
||||
raise ValueError
|
||||
except:
|
||||
raise ValueError('Problem converting %s, routing code must be 0, 5, 9 or 11 digits' % routing)
|
||||
|
||||
tracking = self.tracking
|
||||
svalue = tracking[0:2]
|
||||
try:
|
||||
value *= 10
|
||||
value += int(svalue[0])
|
||||
value *= 5
|
||||
value += int(svalue[1])
|
||||
except:
|
||||
raise ValueError('Problem converting %s, barcode identifier must be 2 digits' % svalue)
|
||||
|
||||
i = 2
|
||||
for name,nd in (('special services',3), ('customer identifier',6), ('sequence number',9)):
|
||||
j = i
|
||||
i += nd
|
||||
svalue = tracking[j:i]
|
||||
try:
|
||||
if len(svalue)!=nd: raise ValueError
|
||||
for j in range(nd):
|
||||
value *= 10
|
||||
value += int(svalue[j])
|
||||
except:
|
||||
raise ValueError('Problem converting %s, %s must be %d digits' % (svalue,name,nd))
|
||||
self._bvalue = value
|
||||
return value
|
||||
binary = property(binary)
|
||||
|
||||
def codewords(self):
|
||||
'''convert binary value into codewords
|
||||
>>> print(USPS_4State('01234567094987654321','01234567891').codewords)
|
||||
(673, 787, 607, 1022, 861, 19, 816, 1294, 35, 602)
|
||||
'''
|
||||
if not self._codewords:
|
||||
value = self.binary
|
||||
A, J = divmod(value,636)
|
||||
A, I = divmod(A,1365)
|
||||
A, H = divmod(A,1365)
|
||||
A, G = divmod(A,1365)
|
||||
A, F = divmod(A,1365)
|
||||
A, E = divmod(A,1365)
|
||||
A, D = divmod(A,1365)
|
||||
A, C = divmod(A,1365)
|
||||
A, B = divmod(A,1365)
|
||||
assert 0<=A<=658, 'improper value %s passed to _2codewords A-->%s' % (hex(int(value)),A)
|
||||
self._fcs = _crc11(value)
|
||||
if self._fcs&1024: A += 659
|
||||
J *= 2
|
||||
self._codewords = tuple(map(int,(A,B,C,D,E,F,G,H,I,J)))
|
||||
return self._codewords
|
||||
codewords = property(codewords)
|
||||
|
||||
|
||||
def table1(self):
|
||||
self.__class__.table1 = _initNof13Table(5,1287)
|
||||
return self.__class__.table1
|
||||
table1 = property(table1)
|
||||
|
||||
def table2(self):
|
||||
self.__class__.table2 = _initNof13Table(2,78)
|
||||
return self.__class__.table2
|
||||
table2 = property(table2)
|
||||
|
||||
def characters(self):
|
||||
''' convert own codewords to characters
|
||||
>>> print(' '.join(hex(c)[2:] for c in USPS_4State('01234567094987654321','01234567891').characters))
|
||||
dcb 85c 8e4 b06 6dd 1740 17c6 1200 123f 1b2b
|
||||
'''
|
||||
if not self._characters:
|
||||
codewords = self.codewords
|
||||
fcs = self._fcs
|
||||
C = []
|
||||
aC = C.append
|
||||
table1 = self.table1
|
||||
table2 = self.table2
|
||||
for i in range(10):
|
||||
cw = codewords[i]
|
||||
if cw<=1286:
|
||||
c = table1[cw]
|
||||
else:
|
||||
c = table2[cw-1287]
|
||||
if (fcs>>i)&1:
|
||||
c = ~c & 0x1fff
|
||||
aC(c)
|
||||
self._characters = tuple(C)
|
||||
return self._characters
|
||||
characters = property(characters)
|
||||
|
||||
def barcodes(self):
|
||||
'''Get 4 state bar codes for current routing and tracking
|
||||
>>> print(USPS_4State('01234567094987654321','01234567891').barcodes)
|
||||
AADTFFDFTDADTAADAATFDTDDAAADDTDTTDAFADADDDTFFFDDTTTADFAAADFTDAADA
|
||||
'''
|
||||
if not self._barcodes:
|
||||
C = self.characters
|
||||
B = []
|
||||
aB = B.append
|
||||
bits2bars = self._bits2bars
|
||||
for dc,db,ac,ab in self.table4:
|
||||
aB(bits2bars[((C[dc]>>db)&1)+2*((C[ac]>>ab)&1)])
|
||||
self._barcodes = ''.join(B)
|
||||
return self._barcodes
|
||||
barcodes = property(barcodes)
|
||||
|
||||
table4 = ((7, 2, 4, 3), (1, 10, 0, 0), (9, 12, 2, 8), (5, 5, 6, 11),
|
||||
(8, 9, 3, 1), (0, 1, 5, 12), (2, 5, 1, 8), (4, 4, 9, 11),
|
||||
(6, 3, 8, 10), (3, 9, 7, 6), (5, 11, 1, 4), (8, 5, 2, 12),
|
||||
(9, 10, 0, 2), (7, 1, 6, 7), (3, 6, 4, 9), (0, 3, 8, 6),
|
||||
(6, 4, 2, 7), (1, 1, 9, 9), (7, 10, 5, 2), (4, 0, 3, 8),
|
||||
(6, 2, 0, 4), (8, 11, 1, 0), (9, 8, 3, 12), (2, 6, 7, 7),
|
||||
(5, 1, 4, 10), (1, 12, 6, 9), (7, 3, 8, 0), (5, 8, 9, 7),
|
||||
(4, 6, 2, 10), (3, 4, 0, 5), (8, 4, 5, 7), (7, 11, 1, 9),
|
||||
(6, 0, 9, 6), (0, 6, 4, 8), (2, 1, 3, 2), (5, 9, 8, 12),
|
||||
(4, 11, 6, 1), (9, 5, 7, 4), (3, 3, 1, 2), (0, 7, 2, 0),
|
||||
(1, 3, 4, 1), (6, 10, 3, 5), (8, 7, 9, 4), (2, 11, 5, 6),
|
||||
(0, 8, 7, 12), (4, 2, 8, 1), (5, 10, 3, 0), (9, 3, 0, 9),
|
||||
(6, 5, 2, 4), (7, 8, 1, 7), (5, 0, 4, 5), (2, 3, 0, 10),
|
||||
(6, 12, 9, 2), (3, 11, 1, 6), (8, 8, 7, 9), (5, 4, 0, 11),
|
||||
(1, 5, 2, 2), (9, 1, 4, 12), (8, 3, 6, 6), (7, 0, 3, 7),
|
||||
(4, 7, 7, 5), (0, 12, 1, 11), (2, 9, 9, 0), (6, 8, 5, 3),
|
||||
(3, 10, 8, 2))
|
||||
|
||||
_bits2bars = 'T','D','A','F'
|
||||
horizontalClearZone = property(lambda self: self.scale('hcz',self.dimensions,self.widthScale))
|
||||
verticalClearZone = property(lambda self: self.scale('vcz',self.dimensions,self.heightScale))
|
||||
|
||||
@property
|
||||
def barWidth(self):
|
||||
if '_barWidth' in self.__dict__:
|
||||
return self.__dict__['_barWidth']
|
||||
return self.scale('width',self.dimensions,self.widthScale)
|
||||
|
||||
@barWidth.setter
|
||||
def barWidth(self,value):
|
||||
n, x = self.dimensions['width']
|
||||
self.__dict__['_barWidth'] = 72*min(max(value/72.0,n),x)
|
||||
|
||||
@property
|
||||
def pitch(self):
|
||||
if '_pitch' in self.__dict__:
|
||||
return self.__dict__['_pitch']
|
||||
return self.scale('pitch',self.dimensions,self.widthScale)
|
||||
|
||||
@pitch.setter
|
||||
def pitch(self,value):
|
||||
n, x = self.dimensions['pitch']
|
||||
self.__dict__['_pitch'] = 72*min(max(value/72.0,n),x)
|
||||
|
||||
@property
|
||||
def barHeight(self):
|
||||
if '_barHeight' in self.__dict__:
|
||||
return self.__dict__['_barHeight']
|
||||
return self.scale('F',self.tops,self.heightScale) - self.scale('F',self.bottoms,self.heightScale)
|
||||
|
||||
@barHeight.setter
|
||||
def barHeight(self,value):
|
||||
n = self.tops['F'][0] - self.bottoms['F'][0]
|
||||
x = self.tops['F'][1] - self.bottoms['F'][1]
|
||||
value = self.__dict__['_barHeight'] = 72*min(max(value/72.0,n),x)
|
||||
self.heightSize = (value - n)/(x-n)
|
||||
|
||||
widthScale = property(lambda self: min(1,max(0,self.widthSize)))
|
||||
heightScale = property(lambda self: min(1,max(0,self.heightSize)))
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
self.computeSize()
|
||||
return self._width
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
self.computeSize()
|
||||
return self._height
|
||||
|
||||
#we ignore attempts to set the dimensions
|
||||
@width.setter
|
||||
def width(self,v):
|
||||
pass
|
||||
@height.setter
|
||||
def height(self,v):
|
||||
pass
|
||||
|
||||
def computeSize(self):
|
||||
if not getattr(self,'_sized',None):
|
||||
ws = self.widthScale
|
||||
hs = self.heightScale
|
||||
barHeight = self.barHeight
|
||||
barWidth = self.barWidth
|
||||
pitch = self.pitch
|
||||
hcz = self.horizontalClearZone
|
||||
vcz = self.verticalClearZone
|
||||
self._width = 2*hcz + barWidth + 64*pitch
|
||||
self._height = 2*vcz+barHeight
|
||||
if self.humanReadable:
|
||||
self._height += self.fontSize*1.2+vcz
|
||||
self._sized = True
|
||||
|
||||
def wrap(self,aW,aH):
|
||||
self.computeSize()
|
||||
return self.width, self.height
|
||||
|
||||
def _getBarVInfo(self,y0=0):
|
||||
vInfo = {}
|
||||
hs = self.heightScale
|
||||
for b in ('T','D','A','F'):
|
||||
y = self.scale(b,self.bottoms,hs)+y0
|
||||
vInfo[b] = y,self.scale(b,self.tops,hs)+y0 - y
|
||||
return vInfo
|
||||
|
||||
def draw(self):
|
||||
self.computeSize()
|
||||
hcz = self.horizontalClearZone
|
||||
vcz = self.verticalClearZone
|
||||
bw = self.barWidth
|
||||
x = hcz
|
||||
y0 = vcz+self.barHeight*0.5
|
||||
dw = self.pitch
|
||||
vInfo = self._getBarVInfo(y0)
|
||||
for b in self.barcodes:
|
||||
yb, hb = vInfo[b]
|
||||
self.rect(x,yb,bw,hb)
|
||||
x += dw
|
||||
self.drawHumanReadable()
|
||||
|
||||
def value(self):
|
||||
tracking = self.tracking
|
||||
routing = self.routing
|
||||
routing = routing and (routing,) or ()
|
||||
return ' '.join((tracking[0:2],tracking[2:5],tracking[5:11],tracking[11:])+routing)
|
||||
value = property(value,lambda self,value: self.__dict__.__setitem__('tracking',value))
|
||||
|
||||
def drawHumanReadable(self):
|
||||
if self.humanReadable:
|
||||
hcz = self.horizontalClearZone
|
||||
vcz = self.verticalClearZone
|
||||
fontName = self.fontName
|
||||
fontSize = self.fontSize
|
||||
y = self.barHeight+2*vcz+0.2*fontSize
|
||||
self.annotate(hcz,y,self.value,fontName,fontSize)
|
||||
|
||||
def annotate(self,x,y,text,fontName,fontSize,anchor='middle'):
|
||||
Barcode.annotate(self,x,y,text,fontName,fontSize,anchor='start')
|
||||
|
||||
def _crc11(value):
|
||||
'''
|
||||
>>> usps = [USPS_4State('01234567094987654321',x).binary for x in ('','01234','012345678','01234567891')]
|
||||
>>> print(' '.join(nhex(x) for x in usps))
|
||||
0x1122103b5c2004b1 0xd138a87bab5cf3804b1 0x202bdc097711204d21804b1 0x16907b2a24abc16a2e5c004b1
|
||||
>>> print(' '.join(nhex(_crc11(x)) for x in usps))
|
||||
0x51 0x65 0x606 0x751
|
||||
'''
|
||||
hexbytes = nhex(int(value))[2:]
|
||||
hexbytes = '0'*(26-len(hexbytes))+hexbytes
|
||||
gp = 0x0F35
|
||||
fcs = 0x07FF
|
||||
data = int(hexbytes[:2],16)<<5
|
||||
for b in range(2,8):
|
||||
if (fcs ^ data)&0x400:
|
||||
fcs = (fcs<<1)^gp
|
||||
else:
|
||||
fcs = fcs<<1
|
||||
fcs &= 0x7ff
|
||||
data <<= 1
|
||||
|
||||
for x in range(2,2*13,2):
|
||||
data = int(hexbytes[x:x+2],16)<<3
|
||||
for b in range(8):
|
||||
if (fcs ^ data)&0x400:
|
||||
fcs = (fcs<<1)^gp
|
||||
else:
|
||||
fcs = fcs<<1
|
||||
fcs &= 0x7ff
|
||||
data <<= 1
|
||||
return fcs
|
||||
|
||||
def _ru13(i):
|
||||
'''reverse unsigned 13 bit number
|
||||
>>> print(_ru13(7936), _ru13(31), _ru13(47), _ru13(7808))
|
||||
31 7936 7808 47
|
||||
'''
|
||||
r = 0
|
||||
for x in range(13):
|
||||
r <<= 1
|
||||
r |= i & 1
|
||||
i >>= 1
|
||||
return r
|
||||
|
||||
def _initNof13Table(N,lenT):
|
||||
'''create and return table of 13 bit values with N bits on
|
||||
>>> T = _initNof13Table(5,1287)
|
||||
>>> print(' '.join('T[%d]=%d' % (i, T[i]) for i in (0,1,2,3,4,1271,1272,1284,1285,1286)))
|
||||
T[0]=31 T[1]=7936 T[2]=47 T[3]=7808 T[4]=55 T[1271]=6275 T[1272]=6211 T[1284]=856 T[1285]=744 T[1286]=496
|
||||
'''
|
||||
T = lenT*[None]
|
||||
l = 0
|
||||
u = lenT-1
|
||||
for c in range(8192):
|
||||
bc = 0
|
||||
for b in range(13):
|
||||
bc += (c&(1<<b))!=0
|
||||
if bc!=N: continue
|
||||
r = _ru13(c)
|
||||
if r<c: continue #we already looked at this pair
|
||||
if r==c:
|
||||
T[u] = c
|
||||
u -= 1
|
||||
else:
|
||||
T[l] = c
|
||||
l += 1
|
||||
T[l] = r
|
||||
l += 1
|
||||
assert l==(u+1), 'u+1(%d)!=l(%d) for %d of 13 table' % (u+1,l,N)
|
||||
return T
|
||||
|
||||
def _test():
|
||||
import doctest
|
||||
return doctest.testmod()
|
||||
|
||||
if __name__ == "__main__":
|
||||
_test()
|
||||
@@ -0,0 +1,357 @@
|
||||
#copyright ReportLab Europe Limited. 2000-2016
|
||||
#see license.txt for license details
|
||||
__version__='3.3.0'
|
||||
__all__= (
|
||||
'BarcodeI2of5',
|
||||
'BarcodeCode128',
|
||||
'BarcodeStandard93',
|
||||
'BarcodeExtended93',
|
||||
'BarcodeStandard39',
|
||||
'BarcodeExtended39',
|
||||
'BarcodeMSI',
|
||||
'BarcodeCodabar',
|
||||
'BarcodeCode11',
|
||||
'BarcodeFIM',
|
||||
'BarcodePOSTNET',
|
||||
'BarcodeUSPS_4State',
|
||||
)
|
||||
|
||||
from reportlab.lib.validators import isInt, isNumber, isString, isColorOrNone, isBoolean, EitherOr, isNumberOrNone
|
||||
from reportlab.lib.attrmap import AttrMap, AttrMapValue
|
||||
from reportlab.lib.colors import black
|
||||
from reportlab.lib.utils import rl_exec
|
||||
from reportlab.graphics.shapes import Rect, Group, String
|
||||
from reportlab.graphics.charts.areas import PlotArea
|
||||
|
||||
'''
|
||||
#snippet
|
||||
|
||||
#first make your Drawing
|
||||
from reportlab.graphics.shapes import Drawing
|
||||
d= Drawing(100,50)
|
||||
|
||||
#create and set up the widget
|
||||
from reportlab.graphics.barcode.widgets import BarcodeStandard93
|
||||
bc = BarcodeStandard93()
|
||||
bc.value = 'RGB-123456'
|
||||
|
||||
#add to the drawing and save
|
||||
d.add(bc)
|
||||
# d.save(formats=['gif','pict'],fnRoot='bc_sample')
|
||||
'''
|
||||
|
||||
class _BarcodeWidget(PlotArea):
|
||||
_attrMap = AttrMap(BASE=PlotArea,
|
||||
barStrokeColor = AttrMapValue(isColorOrNone, desc='Color of bar borders.'),
|
||||
barFillColor = AttrMapValue(isColorOrNone, desc='Color of bar interior areas.'),
|
||||
barStrokeWidth = AttrMapValue(isNumber, desc='Width of bar borders.'),
|
||||
value = AttrMapValue(EitherOr((isString,isNumber)), desc='Value.'),
|
||||
textColor = AttrMapValue(isColorOrNone, desc='Color of human readable text.'),
|
||||
valid = AttrMapValue(isBoolean),
|
||||
validated = AttrMapValue(isString,desc="validated form of input"),
|
||||
encoded = AttrMapValue(None,desc="encoded form of input"),
|
||||
decomposed = AttrMapValue(isString,desc="decomposed form of input"),
|
||||
canv = AttrMapValue(None,desc="temporarily used for internal methods"),
|
||||
gap = AttrMapValue(isNumberOrNone, desc='Width of inter character gaps.'),
|
||||
)
|
||||
|
||||
textColor = barFillColor = black
|
||||
barStrokeColor = None
|
||||
barStrokeWidth = 0
|
||||
_BCC = None
|
||||
def __init__(self,_value='',**kw):
|
||||
PlotArea.__init__(self)
|
||||
if 'width' in self.__dict__: del self.__dict__['width']
|
||||
if 'height' in self.__dict__: del self.__dict__['height']
|
||||
self.x = self.y = 0
|
||||
kw.setdefault('value',_value)
|
||||
self._BCC.__init__(self,**kw)
|
||||
|
||||
def rect(self,x,y,w,h,**kw):
|
||||
#this allows the base code to draw rectangles for us using self.rect
|
||||
#using direct keyword argument overrides see eg common.py line 140 on
|
||||
for k,v in (('strokeColor',self.barStrokeColor),
|
||||
('strokeWidth',self.barStrokeWidth),
|
||||
('fillColor',self.barFillColor)):
|
||||
kw.setdefault(k,v)
|
||||
self._Gadd(Rect(self.x+x,self.y+y,w,h, **kw))
|
||||
|
||||
def draw(self):
|
||||
if not self._BCC: raise NotImplementedError("Abstract class %s cannot be drawn" % self.__class__.__name__)
|
||||
self.canv = self
|
||||
G = Group()
|
||||
self._Gadd = G.add
|
||||
self._Gadd(Rect(self.x,self.y,self.width,self.height,fillColor=None,strokeColor=None,strokeWidth=0.0001))
|
||||
self._BCC.draw(self)
|
||||
del self.canv, self._Gadd
|
||||
return G
|
||||
|
||||
def annotate(self,x,y,text,fontName,fontSize,anchor='middle'):
|
||||
self._Gadd(String(self.x+x,self.y+y,text,fontName=fontName,fontSize=fontSize,
|
||||
textAnchor=anchor,fillColor=self.textColor))
|
||||
|
||||
def _BCW(doc,codeName,attrMap,mod,value,**kwds):
|
||||
"""factory for Barcode Widgets"""
|
||||
_pre_init = kwds.pop('_pre_init','')
|
||||
_methods = kwds.pop('_methods','')
|
||||
name = 'Barcode'+codeName
|
||||
ns = vars().copy()
|
||||
code = 'from %s import %s' % (mod,codeName)
|
||||
rl_exec(code,ns)
|
||||
ns['_BarcodeWidget'] = _BarcodeWidget
|
||||
ns['doc'] = ("\n\t'''%s'''" % doc) if doc else ''
|
||||
code = '''class %(name)s(_BarcodeWidget,%(codeName)s):%(doc)s
|
||||
\t_BCC = %(codeName)s
|
||||
\tcodeName = %(codeName)r
|
||||
\tdef __init__(self,**kw):%(_pre_init)s
|
||||
\t\t_BarcodeWidget.__init__(self,%(value)r,**kw)%(_methods)s''' % ns
|
||||
rl_exec(code,ns)
|
||||
Klass = ns[name]
|
||||
if attrMap: Klass._attrMap = attrMap
|
||||
for k, v in kwds.items():
|
||||
setattr(Klass,k,v)
|
||||
return Klass
|
||||
|
||||
BarcodeI2of5 = _BCW(
|
||||
"""Interleaved 2 of 5 is used in distribution and warehouse industries.
|
||||
|
||||
It encodes an even-numbered sequence of numeric digits. There is an optional
|
||||
module 10 check digit; if including this, the total length must be odd so that
|
||||
it becomes even after including the check digit. Otherwise the length must be
|
||||
even. Since the check digit is optional, our library does not check it.
|
||||
""",
|
||||
"I2of5",
|
||||
AttrMap(BASE=_BarcodeWidget,
|
||||
barWidth = AttrMapValue(isNumber,'''(float, default .0075):
|
||||
X-Dimension, or width of the smallest element
|
||||
Minumum is .0075 inch (7.5 mils).'''),
|
||||
ratio = AttrMapValue(isNumber,'''(float, default 2.2):
|
||||
The ratio of wide elements to narrow elements.
|
||||
Must be between 2.0 and 3.0 (or 2.2 and 3.0 if the
|
||||
barWidth is greater than 20 mils (.02 inch))'''),
|
||||
gap = AttrMapValue(isNumberOrNone,'''(float or None, default None):
|
||||
width of intercharacter gap. None means "use barWidth".'''),
|
||||
barHeight = AttrMapValue(isNumber,'''(float, see default below):
|
||||
Height of the symbol. Default is the height of the two
|
||||
bearer bars (if they exist) plus the greater of .25 inch
|
||||
or .15 times the symbol's length.'''),
|
||||
checksum = AttrMapValue(isBoolean,'''(bool, default 1):
|
||||
Whether to compute and include the check digit'''),
|
||||
bearers = AttrMapValue(isNumber,'''(float, in units of barWidth. default 3.0):
|
||||
Height of bearer bars (horizontal bars along the top and
|
||||
bottom of the barcode). Default is 3 x-dimensions.
|
||||
Set to zero for no bearer bars. (Bearer bars help detect
|
||||
misscans, so it is suggested to leave them on).'''),
|
||||
bearerBox = AttrMapValue(isBoolean,'''(bool, default 0):
|
||||
if True turn bearers into a box'''),
|
||||
quiet = AttrMapValue(isBoolean,'''(bool, default 1):
|
||||
Whether to include quiet zones in the symbol.'''),
|
||||
|
||||
lquiet = AttrMapValue(isNumber,'''(float, see default below):
|
||||
Quiet zone size to left of code, if quiet is true.
|
||||
Default is the greater of .25 inch, or .15 times the symbol's
|
||||
length.'''),
|
||||
|
||||
rquiet = AttrMapValue(isNumber,'''(float, defaults as above):
|
||||
Quiet zone size to right left of code, if quiet is true.'''),
|
||||
fontName = AttrMapValue(isString, desc='human readable font'),
|
||||
fontSize = AttrMapValue(isNumber, desc='human readable font size'),
|
||||
humanReadable = AttrMapValue(isBoolean, desc='if human readable'),
|
||||
stop = AttrMapValue(isBoolean, desc='if we use start/stop symbols (default 1)'),
|
||||
),
|
||||
'reportlab.graphics.barcode.common',
|
||||
1234,
|
||||
_tests = [
|
||||
'12',
|
||||
'1234',
|
||||
'123456',
|
||||
'12345678',
|
||||
'1234567890'
|
||||
],
|
||||
)
|
||||
|
||||
BarcodeCode128 = _BCW("""Code 128 encodes any number of characters in the ASCII character set.""",
|
||||
"Code128",
|
||||
AttrMap(BASE=BarcodeI2of5,UNWANTED=('bearers','checksum','ratio','checksum','stop')),
|
||||
'reportlab.graphics.barcode.code128',
|
||||
"AB-12345678",
|
||||
_tests = ['ReportLab Rocks!', 'PFWZF'],
|
||||
)
|
||||
|
||||
BarcodeCode128Auto = _BCW(
|
||||
'Modified Code128 to use auto encoding',
|
||||
'Code128Auto',
|
||||
AttrMap(BASE=BarcodeCode128),
|
||||
'reportlab.graphics.barcode.code128',
|
||||
'XY149740345GB'
|
||||
)
|
||||
|
||||
BarcodeStandard93=_BCW("""This is a compressed form of Code 39""",
|
||||
"Standard93",
|
||||
AttrMap(BASE=BarcodeCode128,
|
||||
stop = AttrMapValue(isBoolean, desc='if we use start/stop symbols (default 1)'),
|
||||
),
|
||||
'reportlab.graphics.barcode.code93',
|
||||
"CODE 93",
|
||||
)
|
||||
|
||||
BarcodeExtended93=_BCW("""This is a compressed form of Code 39, allowing the full ASCII charset""",
|
||||
"Extended93",
|
||||
AttrMap(BASE=BarcodeCode128,
|
||||
stop = AttrMapValue(isBoolean, desc='if we use start/stop symbols (default 1)'),
|
||||
),
|
||||
'reportlab.graphics.barcode.code93',
|
||||
"L@@K! Code 93 ;-)",
|
||||
)
|
||||
|
||||
BarcodeStandard39=_BCW("""Code39 is widely used in non-retail, especially US defence and health.
|
||||
Allowed characters are 0-9, A-Z (caps only), space, and -.$/+%*.""",
|
||||
"Standard39",
|
||||
AttrMap(BASE=BarcodeI2of5),
|
||||
'reportlab.graphics.barcode.code39',
|
||||
"A012345B%R",
|
||||
)
|
||||
|
||||
BarcodeExtended39=_BCW("""Extended 39 encodes the full ASCII character set by encoding
|
||||
characters as pairs of Code 39 characters; $, /, % and + are used as
|
||||
shift characters.""",
|
||||
"Extended39",
|
||||
AttrMap(BASE=BarcodeI2of5),
|
||||
'reportlab.graphics.barcode.code39',
|
||||
"A012345B}",
|
||||
)
|
||||
|
||||
BarcodeMSI=_BCW("""MSI is used for inventory control in retail applications.
|
||||
|
||||
There are several methods for calculating check digits so we
|
||||
do not implement one.
|
||||
""",
|
||||
"MSI",
|
||||
AttrMap(BASE=BarcodeI2of5),
|
||||
'reportlab.graphics.barcode.common',
|
||||
1234,
|
||||
)
|
||||
|
||||
BarcodeCodabar=_BCW("""Used in blood banks, photo labs and FedEx labels.
|
||||
Encodes 0-9, -$:/.+, and four start/stop characters A-D.""",
|
||||
"Codabar",
|
||||
AttrMap(BASE=BarcodeI2of5),
|
||||
'reportlab.graphics.barcode.common',
|
||||
"A012345B",
|
||||
)
|
||||
|
||||
BarcodeCode11=_BCW("""Used mostly for labelling telecommunications equipment.
|
||||
It encodes numeric digits.""",
|
||||
'Code11',
|
||||
AttrMap(BASE=BarcodeI2of5,
|
||||
checksum = AttrMapValue(isInt,'''(integer, default 2):
|
||||
Whether to compute and include the check digit(s).
|
||||
(0 none, 1 1-digit, 2 2-digit, -1 auto, default -1):
|
||||
How many checksum digits to include. -1 ("auto") means
|
||||
1 if the number of digits is 10 or less, else 2.'''),
|
||||
),
|
||||
'reportlab.graphics.barcode.common',
|
||||
"01234545634563",
|
||||
)
|
||||
|
||||
BarcodeFIM=_BCW("""
|
||||
FIM was developed as part of the POSTNET barcoding system.
|
||||
FIM (Face Identification Marking) is used by the cancelling machines
|
||||
to sort mail according to whether or not they have bar code
|
||||
and their postage requirements. There are four types of FIM
|
||||
called FIM A, FIM B, FIM C, and FIM D.
|
||||
|
||||
The four FIM types have the following meanings:
|
||||
FIM A- Postage required pre-barcoded
|
||||
FIM B - Postage pre-paid, no bar code exists
|
||||
FIM C- Postage prepaid prebarcoded
|
||||
FIM D- Postage required, no bar code exists""",
|
||||
"FIM",
|
||||
AttrMap(BASE=_BarcodeWidget,
|
||||
barWidth = AttrMapValue(isNumber,'''(float, default 1/32in): the bar width.'''),
|
||||
spaceWidth = AttrMapValue(isNumber,'''(float or None, default 1/16in):
|
||||
width of intercharacter gap. None means "use barWidth".'''),
|
||||
barHeight = AttrMapValue(isNumber,'''(float, default 5/8in): The bar height.'''),
|
||||
quiet = AttrMapValue(isBoolean,'''(bool, default 0):
|
||||
Whether to include quiet zones in the symbol.'''),
|
||||
lquiet = AttrMapValue(isNumber,'''(float, default: 15/32in):
|
||||
Quiet zone size to left of code, if quiet is true.'''),
|
||||
rquiet = AttrMapValue(isNumber,'''(float, default 1/4in):
|
||||
Quiet zone size to right left of code, if quiet is true.'''),
|
||||
fontName = AttrMapValue(isString, desc='human readable font'),
|
||||
fontSize = AttrMapValue(isNumber, desc='human readable font size'),
|
||||
humanReadable = AttrMapValue(isBoolean, desc='if human readable'),
|
||||
),
|
||||
'reportlab.graphics.barcode.usps',
|
||||
"A",
|
||||
)
|
||||
|
||||
BarcodePOSTNET=_BCW('',
|
||||
"POSTNET",
|
||||
AttrMap(BASE=_BarcodeWidget,
|
||||
barWidth = AttrMapValue(isNumber,'''(float, default 0.018*in): the bar width.'''),
|
||||
spaceWidth = AttrMapValue(isNumber,'''(float or None, default 0.0275in): width of intercharacter gap.'''),
|
||||
shortHeight = AttrMapValue(isNumber,'''(float, default 0.05in): The short bar height.'''),
|
||||
barHeight = AttrMapValue(isNumber,'''(float, default 0.125in): The full bar height.'''),
|
||||
fontName = AttrMapValue(isString, desc='human readable font'),
|
||||
fontSize = AttrMapValue(isNumber, desc='human readable font size'),
|
||||
humanReadable = AttrMapValue(isBoolean, desc='if human readable'),
|
||||
),
|
||||
'reportlab.graphics.barcode.usps',
|
||||
"78247-1043",
|
||||
)
|
||||
|
||||
BarcodeUSPS_4State=_BCW('',
|
||||
"USPS_4State",
|
||||
AttrMap(BASE=_BarcodeWidget,
|
||||
widthSize = AttrMapValue(isNumber,'''(float, default 1): the bar width size adjustment between 0 and 1.'''),
|
||||
heightSize = AttrMapValue(isNumber,'''(float, default 1): the bar height size adjustment between 0 and 1.'''),
|
||||
fontName = AttrMapValue(isString, desc='human readable font'),
|
||||
fontSize = AttrMapValue(isNumber, desc='human readable font size'),
|
||||
tracking = AttrMapValue(isString, desc='tracking data'),
|
||||
routing = AttrMapValue(isString, desc='routing data'),
|
||||
humanReadable = AttrMapValue(isBoolean, desc='if human readable'),
|
||||
barWidth = AttrMapValue(isNumber, desc='barWidth'),
|
||||
barHeight = AttrMapValue(isNumber, desc='barHeight'),
|
||||
pitch = AttrMapValue(isNumber, desc='pitch'),
|
||||
),
|
||||
'reportlab.graphics.barcode.usps4s',
|
||||
'01234567094987654321',
|
||||
_pre_init="\n\t\tkw.setdefault('routing','01234567891')\n",
|
||||
_methods = "\n\tdef annotate(self,x,y,text,fontName,fontSize,anchor='middle'):\n\t\t_BarcodeWidget.annotate(self,x,y,text,fontName,fontSize,anchor='start')\n"
|
||||
)
|
||||
BarcodeECC200DataMatrix = _BCW(
|
||||
'ECC200DataMatrix',
|
||||
'ECC200DataMatrix',
|
||||
AttrMap(BASE=_BarcodeWidget,
|
||||
x=AttrMapValue(isNumber, desc='X position of the lower-left corner of the barcode.'),
|
||||
y=AttrMapValue(isNumber, desc='Y position of the lower-left corner of the barcode.'),
|
||||
barWidth=AttrMapValue(isNumber, desc='Size of data modules.'),
|
||||
barFillColor=AttrMapValue(isColorOrNone, desc='Color of data modules.'),
|
||||
value=AttrMapValue(EitherOr((isString,isNumber)), desc='Value.'),
|
||||
height=AttrMapValue(None, desc='ignored'),
|
||||
width=AttrMapValue(None, desc='ignored'),
|
||||
strokeColor=AttrMapValue(None, desc='ignored'),
|
||||
strokeWidth=AttrMapValue(None, desc='ignored'),
|
||||
fillColor=AttrMapValue(None, desc='ignored'),
|
||||
background=AttrMapValue(None, desc='ignored'),
|
||||
debug=AttrMapValue(None, desc='ignored'),
|
||||
gap=AttrMapValue(None, desc='ignored'),
|
||||
row_modules=AttrMapValue(None, desc='???'),
|
||||
col_modules=AttrMapValue(None, desc='???'),
|
||||
row_regions=AttrMapValue(None, desc='???'),
|
||||
col_regions=AttrMapValue(None, desc='???'),
|
||||
cw_data=AttrMapValue(None, desc='???'),
|
||||
cw_ecc=AttrMapValue(None, desc='???'),
|
||||
row_usable_modules = AttrMapValue(None, desc='???'),
|
||||
col_usable_modules = AttrMapValue(None, desc='???'),
|
||||
valid = AttrMapValue(None, desc='???'),
|
||||
validated = AttrMapValue(None, desc='???'),
|
||||
decomposed = AttrMapValue(None, desc='???'),
|
||||
),
|
||||
'reportlab.graphics.barcode.ecc200datamatrix',
|
||||
'JGB 0204H20B012722900021AC35B2100001003241014241014TPS01 WJ067073605GB185 MOUNT PLEASANT MAIL CENTER EC1A1BB9ZGBREC1A1BB EC1A1BB STEST FILE FOR SPEC '
|
||||
)
|
||||
|
||||
if __name__=='__main__':
|
||||
raise ValueError('widgets.py has no script function')
|
||||
@@ -0,0 +1,5 @@
|
||||
#Copyright ReportLab Europe Ltd. 2000-2017
|
||||
#see license.txt for license details
|
||||
#history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/charts/__init__.py
|
||||
__version__='3.3.0'
|
||||
__doc__='''Business charts'''
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,94 @@
|
||||
#Copyright ReportLab Europe Ltd. 2000-2017
|
||||
#see license.txt for license details
|
||||
#history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/charts/areas.py
|
||||
|
||||
__version__='3.3.0'
|
||||
__doc__='''This module defines a Area mixin classes'''
|
||||
|
||||
from reportlab.lib.validators import isNumber, isColorOrNone, isNoneOrShape
|
||||
from reportlab.graphics.widgetbase import Widget
|
||||
from reportlab.graphics.shapes import Rect, Group, Line, Polygon
|
||||
from reportlab.lib.attrmap import AttrMap, AttrMapValue
|
||||
from reportlab.lib.colors import grey
|
||||
|
||||
class PlotArea(Widget):
|
||||
"Abstract base class representing a chart's plot area, pretty unusable by itself."
|
||||
_attrMap = AttrMap(
|
||||
x = AttrMapValue(isNumber, desc='X position of the lower-left corner of the chart.'),
|
||||
y = AttrMapValue(isNumber, desc='Y position of the lower-left corner of the chart.'),
|
||||
width = AttrMapValue(isNumber, desc='Width of the chart.'),
|
||||
height = AttrMapValue(isNumber, desc='Height of the chart.'),
|
||||
strokeColor = AttrMapValue(isColorOrNone, desc='Color of the plot area border.'),
|
||||
strokeWidth = AttrMapValue(isNumber, desc='Width plot area border.'),
|
||||
fillColor = AttrMapValue(isColorOrNone, desc='Color of the plot area interior.'),
|
||||
background = AttrMapValue(isNoneOrShape, desc='Handle to background object e.g. Rect(0,0,width,height).'),
|
||||
debug = AttrMapValue(isNumber, desc='Used only for debugging.'),
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self.x = 20
|
||||
self.y = 10
|
||||
self.height = 85
|
||||
self.width = 180
|
||||
self.strokeColor = None
|
||||
self.strokeWidth = 1
|
||||
self.fillColor = None
|
||||
self.background = None
|
||||
self.debug = 0
|
||||
|
||||
def makeBackground(self):
|
||||
if self.background is not None:
|
||||
BG = self.background
|
||||
if isinstance(BG,Group):
|
||||
g = BG
|
||||
for bg in g.contents:
|
||||
bg.x = self.x
|
||||
bg.y = self.y
|
||||
bg.width = self.width
|
||||
bg.height = self.height
|
||||
else:
|
||||
g = Group()
|
||||
if type(BG) not in (type(()),type([])): BG=(BG,)
|
||||
for bg in BG:
|
||||
bg.x = self.x
|
||||
bg.y = self.y
|
||||
bg.width = self.width
|
||||
bg.height = self.height
|
||||
g.add(bg)
|
||||
return g
|
||||
else:
|
||||
strokeColor,strokeWidth,fillColor=self.strokeColor, self.strokeWidth, self.fillColor
|
||||
if (strokeWidth and strokeColor) or fillColor:
|
||||
g = Group()
|
||||
_3d_dy = getattr(self,'_3d_dy',None)
|
||||
x = self.x
|
||||
y = self.y
|
||||
h = self.height
|
||||
w = self.width
|
||||
if _3d_dy is not None:
|
||||
_3d_dx = self._3d_dx
|
||||
if fillColor and not strokeColor:
|
||||
from reportlab.lib.colors import Blacker
|
||||
c = Blacker(fillColor, getattr(self,'_3d_blacken',0.7))
|
||||
else:
|
||||
c = strokeColor
|
||||
if not strokeWidth: strokeWidth = 0.5
|
||||
if fillColor or strokeColor or c:
|
||||
bg = Polygon([x,y,x,y+h,x+_3d_dx,y+h+_3d_dy,x+w+_3d_dx,y+h+_3d_dy,x+w+_3d_dx,y+_3d_dy,x+w,y],
|
||||
strokeColor=strokeColor or c or grey, strokeWidth=strokeWidth, fillColor=fillColor)
|
||||
g.add(bg)
|
||||
g.add(Line(x,y,x+_3d_dx,y+_3d_dy, strokeWidth=0.5, strokeColor=c))
|
||||
g.add(Line(x+_3d_dx,y+_3d_dy, x+_3d_dx,y+h+_3d_dy,strokeWidth=0.5, strokeColor=c))
|
||||
fc = Blacker(c, getattr(self,'_3d_blacken',0.8))
|
||||
g.add(Polygon([x,y,x+_3d_dx,y+_3d_dy,x+w+_3d_dx,y+_3d_dy,x+w,y],
|
||||
strokeColor=strokeColor or c or grey, strokeWidth=strokeWidth, fillColor=fc))
|
||||
bg = Line(x+_3d_dx,y+_3d_dy, x+w+_3d_dx,y+_3d_dy,strokeWidth=0.5, strokeColor=c)
|
||||
else:
|
||||
bg = None
|
||||
else:
|
||||
bg = Rect(x, y, w, h,
|
||||
strokeColor=strokeColor, strokeWidth=strokeWidth, fillColor=fillColor)
|
||||
if bg: g.add(bg)
|
||||
return g
|
||||
else:
|
||||
return None
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user