Start of converting the module to a proper package.

This commit is contained in:
Stephan Richter 2014-02-28 22:57:40 -05:00 committed by josch
parent 8c293291c5
commit b47cc04dd3
3 changed files with 122 additions and 49 deletions

36
setup.py Normal file
View file

@ -0,0 +1,36 @@
from setuptools import setup
setup (
name='img2pdf',
version='0.1.0',
author = "Johannes 'josch' Schauer",
description = "Convert images to PDF via direct JPEG inclusion.",
long_description = open('README.md').read(),
license = "GPL",
keywords = "jpeg pdf converter",
classifiers = [
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: Implementation :: CPython',
'License :: OSI Approved :: General Public License',
'Programming Language :: Python',
'Natural Language :: English',
'Operating System :: OS Independent'],
url = 'http://pypi.python.org/pypi/img2pdf',
package_dir={"": "src"},
py_modules=['img2pdf', 'jp2'],
include_package_data = True,
test_suite = 'tests.test_suite',
zip_safe = True,
install_requires=(
'Pillow',
),
entry_points='''
[console_scripts]
img2pdf = img2pdf:main
''',
)

View file

@ -1,5 +1,3 @@
#!/usr/bin/env python
#
# Copyright (C) 2012-2013 Johannes 'josch' Schauer <j.schauer at email.de> # Copyright (C) 2012-2013 Johannes 'josch' Schauer <j.schauer at email.de>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
@ -15,17 +13,19 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import Image
import sys import sys
import zlib import zlib
import argparse import argparse
import struct import struct
from Pillow import Image
from datetime import datetime from datetime import datetime
from jp2 import parsejp2 from jp2 import parsejp2
def parse(cont, indent=1): def parse(cont, indent=1):
if type(cont) is dict: if type(cont) is dict:
return "<<\n"+"\n".join([4*indent*" "+"%s %s"%(k, parse(v, indent+1)) for k, v in cont.items()])+"\n"+4*(indent-1)*" "+">>" return "<<\n"+"\n".join(
[4 * indent * " " + "%s %s" % (k, parse(v, indent+1))
for k, v in cont.items()])+"\n"+4*(indent-1)*" "+">>"
elif type(cont) is int or type(cont) is float: elif type(cont) is int or type(cont) is float:
return str(cont) return str(cont)
elif isinstance(cont, obj): elif isinstance(cont, obj):
@ -35,26 +35,29 @@ def parse(cont, indent=1):
elif type(cont) is list: elif type(cont) is list:
return "[ "+" ".join([parse(c, indent) for c in cont])+" ]" return "[ "+" ".join([parse(c, indent) for c in cont])+" ]"
class obj(): class obj(object):
def __init__(self, content, stream=None): def __init__(self, content, stream=None):
self.content = content self.content = content
self.stream = stream self.stream = stream
def tostring(self): def tostring(self):
if self.stream: if self.stream:
return "%d 0 obj "%self.identifier+parse(self.content)+"\nstream\n"+self.stream+"\nendstream\nendobj\n" return "%d 0 obj " % (
self.identifier+parse(self.content) +
"\nstream\n" + self.stream + "\nendstream\nendobj\n")
else: else:
return "%d 0 obj "%self.identifier+parse(self.content)+" endobj\n" return "%d 0 obj "%self.identifier+parse(self.content)+" endobj\n"
class pdfdoc(): class pdfdoc(object):
objects = list()
def __init__(self, version=3, title=None, author=None, creator=None, producer=None, def __init__(self, version=3, title=None, author=None, creator=None,
creationdate=None, moddate=None, subject=None, keywords=None): producer=None, creationdate=None, moddate=None, subject=None,
keywords=None):
self.version = version # default pdf version 1.3 self.version = version # default pdf version 1.3
now = datetime.now() now = datetime.now()
objects = []
info = dict() info = {}
if title: if title:
info["/Title"] = "("+title+")" info["/Title"] = "("+title+")"
if author: if author:
@ -78,7 +81,8 @@ class pdfdoc():
self.info = obj(info) self.info = obj(info)
# create an incomplete pages object so that a /Parent entry can be added to each page # create an incomplete pages object so that a /Parent entry can be
# added to each page
self.pages = obj({ self.pages = obj({
"/Type": "/Pages", "/Type": "/Pages",
"/Kids": [], "/Kids": [],
@ -106,7 +110,8 @@ class pdfdoc():
error_out("unsupported color space: %s"%color) error_out("unsupported color space: %s"%color)
exit(1) exit(1)
pdf_x, pdf_y = 72.0*width/dpi[0], 72.0*height/dpi[1] # pdf units = 1/72 inch # pdf units = 1/72 inch
pdf_x, pdf_y = 72.0*width/dpi[0], 72.0*height/dpi[1]
if pdf_x < 3.00 or pdf_y < 3.00: if pdf_x < 3.00 or pdf_y < 3.00:
warning_out("pdf width or height is below 3.00 - decrease the dpi") warning_out("pdf width or height is below 3.00 - decrease the dpi")
@ -126,7 +131,8 @@ class pdfdoc():
"/Width": width, "/Width": width,
"/Height": height, "/Height": height,
"/ColorSpace": color, "/ColorSpace": color,
"/BitsPerComponent": 8, # hardcoded as PIL doesnt provide bits for non-jpeg formats # hardcoded as PIL doesnt provide bits for non-jpeg formats
"/BitsPerComponent": 8,
"/Length": len(imgdata) "/Length": len(imgdata)
}, imgdata) }, imgdata)
@ -178,7 +184,7 @@ class pdfdoc():
result += "%%EOF\n" result += "%%EOF\n"
return result return result
def main(images, dpi, title=None, author=None, creator=None, producer=None, def convert(images, dpi, title=None, author=None, creator=None, producer=None,
creationdate=None, moddate=None, subject=None, keywords=None, creationdate=None, moddate=None, subject=None, keywords=None,
colorspace=None, verbose=False): colorspace=None, verbose=False):
@ -190,7 +196,8 @@ def main(images, dpi, title=None, author=None, creator=None, producer=None,
def warning_out(message): def warning_out(message):
sys.stderr.write("W: "+message+"\n") sys.stderr.write("W: "+message+"\n")
pdf = pdfdoc(3, title, author, creator, producer, creationdate, moddate, subject, keywords) pdf = pdfdoc(3, title, author, creator, producer, creationdate,
moddate, subject, keywords)
for im in images: for im in images:
rawdata = im.read() rawdata = im.read()
@ -261,34 +268,64 @@ def main(images, dpi, title=None, author=None, creator=None, producer=None,
return pdf.tostring() return pdf.tostring()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='lossless conversion/embedding of images (in)to pdf')
parser.add_argument('images', metavar='infile', type=argparse.FileType('rb'),
nargs='+', help='input file(s)')
parser.add_argument('-o', '--output', metavar='out', type=argparse.FileType('wb'),
default=sys.stdout, help='output file (default: stdout)')
def positive_float(string): def positive_float(string):
value = float(string) value = float(string)
if value <= 0: if value <= 0:
msg = "%r is not positive"%string msg = "%r is not positive"%string
raise argparse.ArgumentTypeError(msg) raise argparse.ArgumentTypeError(msg)
return value return value
parser.add_argument('-d', '--dpi', metavar='dpi', type=positive_float, help='dpi for pdf output (default: 96.0)')
parser.add_argument('-t', '--title', metavar='title', type=str, help='title for metadata')
parser.add_argument('-a', '--author', metavar='author', type=str, help='author for metadata')
parser.add_argument('-c', '--creator', metavar='creator', type=str, help='creator for metadata')
parser.add_argument('-p', '--producer', metavar='producer', type=str, help='producer for metadata')
def valid_date(string): def valid_date(string):
return datetime.strptime(string, "%Y-%m-%dT%H:%M:%S") return datetime.strptime(string, "%Y-%m-%dT%H:%M:%S")
parser.add_argument('-r', '--creationdate', metavar='creationdate',
type=valid_date, help='creation date for metadata in YYYY-MM-DDTHH:MM:SS format') parser = argparse.ArgumentParser(
parser.add_argument('-m', '--moddate', metavar='moddate', description='Lossless conversion/embedding of images (in)to pdf')
type=valid_date, help='modification date for metadata in YYYY-MM-DDTHH:MM:SS format') parser.add_argument(
parser.add_argument('-s', '--subject', metavar='subject', type=str, help='subject for metadata') 'images', metavar='infile', type=argparse.FileType('rb'),
parser.add_argument('-k', '--keywords', metavar='kw', type=str, nargs='+', help='keywords for metadata') nargs='+', help='input file(s)')
parser.add_argument('-C', '--colorspace', metavar='colorspace', type=str, help='force PIL colorspace (one of: RGB, L, 1)') parser.add_argument(
parser.add_argument('-v', '--verbose', help='verbose mode', action="store_true") '-o', '--output', metavar='out', type=argparse.FileType('wb'),
args = parser.parse_args() default=sys.stdout, help='output file (default: stdout)')
args.output.write(main(args.images, args.dpi, args.title, args.author, parser.add_argument(
'-d', '--dpi', metavar='dpi', type=positive_float,
help='dpi for pdf output (default: 96.0)')
parser.add_argument(
'-t', '--title', metavar='title', type=str,
help='title for metadata')
parser.add_argument(
'-a', '--author', metavar='author', type=str,
help='author for metadata')
parser.add_argument(
'-c', '--creator', metavar='creator', type=str,
help='creator for metadata')
parser.add_argument(
'-p', '--producer', metavar='producer', type=str,
help='producer for metadata')
parser.add_argument(
'-r', '--creationdate', metavar='creationdate', type=valid_date,
help='creation date for metadata in YYYY-MM-DDTHH:MM:SS format')
parser.add_argument(
'-m', '--moddate', metavar='moddate', type=valid_date,
help='modification date for metadata in YYYY-MM-DDTHH:MM:SS format')
parser.add_argument(
'-s', '--subject', metavar='subject', type=str,
help='subject for metadata')
parser.add_argument(
'-k', '--keywords', metavar='kw', type=str, nargs='+',
help='keywords for metadata')
parser.add_argument(
'-C', '--colorspace', metavar='colorspace', type=str,
help='force PIL colorspace (one of: RGB, L, 1)')
parser.add_argument(
'-v', '--verbose', help='verbose mode', action="store_true")
def main(args=None):
if args is None:
args = sys.argv[1:]
args = parser.parse_args(args)
args.output.write(
convert(
args.images, args.dpi, args.title, args.author,
args.creator, args.producer, args.creationdate, args.moddate, args.creator, args.producer, args.creationdate, args.moddate,
args.subject, args.keywords, args.colorspace, args.verbose)) args.subject, args.keywords, args.colorspace, args.verbose))

View file