PK Fb@: dummypdf/__init__.py#!/usr/bin/env python3
# Copyright Louis Paternault 2014-2015
# 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 3 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, see . 1
"""Generate dummy pdf files with configurable paper size and number of pages."""
VERSION = "0.1.1"
__AUTHOR__ = "Louis Paternault (spalax@gresille.org)"
__COPYRIGHT__ = "(C) 2014-2015 Louis Paternault. GNU GPL 3 or later."
PK LF螮] dummypdf/pdf.py#!/usr/bin/env python3
# Copyright Louis Paternault 2011-2015
# 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 3 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, see . 1
"""PDF generation."""
from reportlab.lib import colors
from reportlab.pdfgen import canvas
import papersize
from dummypdf import errors
LINEWIDTH = 5
# Very very approximate size of a "Times-Roman" digit, in font 1
CHARWIDTH = 0.497923228
CHARHEIGHT = 0.704205709
def shift(coordinate):
"""Shift line coordinate.
If we do not do that, half of lines are printed outside the page.
"""
if coordinate == 0:
return LINEWIDTH // 2
else:
return coordinate - LINEWIDTH // 2
def generate(name, first, last, color, paperformat):
"""Generate the pdf.
Arguments:
- name: file name
- first: number of first page
- last: number of last page
- color: line colors, as a list of three colors (RGB, from 0 to 255) or a
named color recognisez by reportlab.
- paperformat: paper format, as a tuple of dimensions, in points.
"""
# pylint: disable=too-many-locals
pdf = canvas.Canvas(name, pagesize=paperformat)
paperwidth, paperheight = paperformat
if isinstance(color, list):
red, green, blue = color
def set_line_color():
"""Set color of lines, using RGB color"""
pdf.setFillColorRGB(red/255, green/255, blue/255)
pdf.setStrokeColorRGB(red/255, green/255, blue/255)
elif isinstance(color, str):
def set_line_color():
"""Set color of lines, using named color"""
pdf.setFillColor(getattr(colors, color))
pdf.setStrokeColor(getattr(colors, color))
if papersize.is_portrait(paperwidth, paperheight):
fontsize = int(float(paperheight)/(3*CHARHEIGHT))
else:
fontsize = int(float(paperheight)/(2*CHARHEIGHT))
charnumber = max([len(str(page)) for page in range(first, last+1)])
if charnumber*CHARWIDTH*fontsize > 0.9 * float(paperwidth):
fontsize = int(0.9 * float(paperwidth) / (charnumber * CHARWIDTH))
for page in range(first, last+1):
# Drawing lines
set_line_color()
pdf.setLineWidth(LINEWIDTH)
for x1, y1, x2, y2 in [ # pylint: disable=invalid-name
(0, 0, paperwidth, 0),
(paperwidth, 0, paperwidth, paperheight),
(paperwidth, paperheight, 0, paperheight),
(0, paperheight, 0, 0),
]:
pdf.line(
shift(x1),
shift(y1),
shift(x2),
shift(y2),
)
pdf.line(paperwidth, paperheight, 0, 0)
pdf.line(paperwidth, 0, 0, paperheight)
# Drawing text
pdf.setFont("Times-Roman", fontsize)
pdf.setFillColor(colors.lightgrey)
pdf.drawCentredString(float(paperwidth)//2, float(paperheight)//2-0.33*fontsize, str(page))
# Next page
pdf.showPage()
pdf.setAuthor("Generated using dummypdf — http://git.framasoft.org/spalax/dummypdf")
pdf.setTitle("Dummy pdf")
pdf.save()
def get_color(name=None):
"""Return color names.
If name is None, return the list of available colors (as strings).
If name is a string, return the string if this color exists; raises an
error otherwise.
"""
available = [color for color in dir(colors) if isinstance(getattr(colors, color), colors.Color)]
if name is None:
return available
elif name in available:
return name
else:
raise errors.ArgumentError(
"No such color '{}'. See help for the list of available colors."
.format(name))
PK SFĦ dummypdf/errors.py#!/usr/bin/env python3
# Copyright Louis Paternault 2011-2015
# 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 3 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, see . 1
"""Errors and exceptions"""
class DummyPdfError(Exception):
"""Generic error for dummypdf"""
pass
class ArgumentError(DummyPdfError):
"""Arguments provided by user where wrong."""
def __init__(self, message):
super().__init__()
self.message = message
def __str__(self):
return self.message
PK 9HP` ` dummypdf/main.py#!/usr/bin/env python3
# Copyright Louis Paternault 2011-2015
# 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 3 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, see . 1
"""Generate dummy pdf files"""
import argparse
import logging
import papersize
import random
import re
import sys
import textwrap
from dummypdf import VERSION
from dummypdf import errors
from dummypdf.pdf import generate, get_color
import dummypdf
LOGGER = logging.getLogger(dummypdf.__name__)
LOGGER.addHandler(logging.StreamHandler())
def positive_int(arg):
"""Return a positive argument corresponding to ``arg``."""
try:
number = int(arg)
except ValueError:
raise argparse.ArgumentTypeError(arg)
if number <= 0:
raise argparse.ArgumentTypeError(arg)
return number
def filename(extension=None):
"""Return the filename.
- If no argument is provided, return the bare file name.
- If an argument is provided, it is the extension of the file to be
returned.
"""
if extension is None:
return "dummy"
else:
return "dummy.{}".format(extension)
def type_papersize(text):
"""Parse 'text' as the argument of --papersize.
Return a tuple of :class:`decimal.Decimal`.
"""
try:
return papersize.parse_papersize(text)
except papersize.PapersizeException as error:
raise argparse.ArgumentTypeError(str(error))
def commandline_parser():
"""Return a command line parser."""
parser = argparse.ArgumentParser(
description="Generate dummy PDF",
formatter_class=argparse.RawTextHelpFormatter,
)
parser.add_argument(
'--version',
help='Show version',
action='version',
version='%(prog)s ' + VERSION
)
parser.add_argument(
'--file', '-f',
default=filename('pdf'),
help=(
'Destination file. Default is "dummy.pdf".'
),
type=str,
)
parser.add_argument(
'--number', '-n',
help="Number of pages.",
default=1,
type=positive_int,
)
parser.add_argument(
'--orientation', '-o',
help="Paper orientation. Default depends on the paper size.",
default=None,
choices=["portrait", "landscape"],
)
parser.add_argument(
'--start', '-s',
help="Number of first page.",
default=1,
type=int,
)
parser.add_argument(
'--papersize', '-p',
default="a4",
type=type_papersize,
help=textwrap.dedent("""
Paper size, as either a named size (e.g. "A4" or "letter"), or a couple
of lengths (e.g. "21cmx29.7cm" or "7in 8in"…). Default value is A4.
"""),
)
parser.add_argument(
'--color', '-c',
default='deterministic',
help=textwrap.dedent("""
Color to use. Can be:
- deterministic (default): a random color is used, but calls to
dummypdf using the same arguments give the same color (note that
calls with different version of this program may lead to different
colors used).
- random: a random color is used (different on each call).
- RED,GREEN,BLUE: a RGB color, where RED, GREEN and BLUE are integers
between 0 and 255.
- named colors: {colors}.
""".format(
colors=", ".join(str(color) for color in get_color()),
)),
)
return parser
def process_options(options):
"Return processed options (might catch errors unnoticed by :mod:`argparse`."
processed = {}
processed['first'] = options.start
processed['orientation'] = options.orientation
processed['last'] = options.start + options.number - 1
processed['file'] = options.file
if options.papersize is None:
pass
else:
processed['paperformat'] = options.papersize
color_re = re.compile(r'(?P\w+),(?P\w+),(?P\w+)')
if options.color.lower() in ['deterministic', 'random']:
if options.color.lower() == 'deterministic':
random.seed("-".join(str(item) for item in [
processed['first'],
processed['last'],
options.papersize,
]))
processed['color'] = [
random.randint(64, 255),
random.randint(0, 191),
random.randint(0, 255),
]
random.shuffle(processed['color'])
elif color_re.match(options.color):
processed['color'] = [int(color) for color in color_re.match(options.color).groups()]
for color in processed['color']:
if color > 255:
raise errors.ArgumentError(
"Option '--color' must be an integer between 0 and 255."
)
else:
processed['color'] = get_color(options.color)
return processed
def main():
"""Main function"""
try:
options = process_options(commandline_parser().parse_args(sys.argv[1:]))
generate(
name=options["file"],
first=options["first"],
last=options["last"],
color=options["color"],
paperformat=options["paperformat"],
)
except errors.DummyPdfError as error:
LOGGER.error(error)
sys.exit(1)
except KeyboardInterrupt:
sys.exit(1)
if __name__ == "__main__":
main()
PK ۳9HS< < ( DummyPdf-0.1.1.dist-info/DESCRIPTION.rstdummypdf — Generate dummy pdf files
===================================
|sources| |pypi| |documentation| |license|
Paper size and number of pages are configurable. Files can be used to test pdf
manipulation tools.
Examples :
- One page A4 paper: `example1.pdf `__.
- Six pages, a third of an A4 paper: `example2.pdf `__.
What's new?
-----------
See `changelog
`_.
Download and install
--------------------
See the end of list for a (quick and dirty) Debian package.
* From sources:
* Download: https://pypi.python.org/pypi/dummypdf
* Install (in a `virtualenv`, if you do not want to mess with your distribution installation system)::
python3 setup.py install
* From pip::
pip install dummypdf
* Quick and dirty Debian (and Ubuntu?) package
This requires `stdeb `_ to be installed::
python3 setup.py --command-packages=stdeb.command bdist_deb
sudo dpkg -i deb_dist/dummypdf-_all.deb
Documentation
-------------
* The compiled documentation is available on `readthedocs
`_
* To compile it from source, download and run::
cd doc && make html
.. |documentation| image:: http://readthedocs.org/projects/dummypdf/badge
:target: http://dummypdf.readthedocs.org
.. |pypi| image:: https://img.shields.io/pypi/v/dummypdf.svg
:target: http://pypi.python.org/pypi/dummypdf
.. |license| image:: https://img.shields.io/pypi/l/dummypdf.svg
:target: http://www.gnu.org/licenses/gpl-3.0.html
.. |sources| image:: https://img.shields.io/badge/sources-dummypdf-brightgreen.svg
:target: http://git.framasoft.org/spalax/dummypdf
PK ֳ9HJ1 1 ) DummyPdf-0.1.1.dist-info/entry_points.txt[console_scripts]
dummypdf = dummypdf.main:main
PK ۳9H& &