Initial commit: IT Site Survey AI v2 with all features

This commit is contained in:
BeawIT Admin
2026-07-03 02:06:55 +00:00
commit b4fff79eda
1985 changed files with 437461 additions and 0 deletions
@@ -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
@@ -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
@@ -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
@@ -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'''
@@ -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)
@@ -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'''
@@ -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