[impression] impression via l'interface web

This commit is contained in:
Daniel STAN 2013-03-17 21:01:56 +01:00
parent 7ab984dc69
commit ebe94de094
3 changed files with 247 additions and 2 deletions

200
impression/canon_wrapper.py Executable file
View file

@ -0,0 +1,200 @@
#!/usr/bin/python
# -*- encoding: utf-8 -*-
import requests #pip install requests
# See:
# http://docs.python-requests.org/en/latest/user/quickstart/#post-a-multipart-encoded-file
import os, os.path, sys
import time
import argparse
import types
import tempfile, atexit
import subprocess
from syslog import syslog, openlog
BASE_URL = "http://imprimante.adm.crans.org"
URIs = {
'root': '/',
'ended_jobs_csv': '/pprint.csv?Flag=Csv_Data&LogType=0&Dummy=%(timestamp)s',
'current_jobs': '/jpl.cgi?Flag=Init_Data&CorePGTAG=6&Dummy=%(timestamp)s',
'print': '/ppdf.cgi?Type=PDF&Dummy=%(timestamp)s',
'do_print': '/pprint.cgi',
}
STAPLE_POSITIONS={"TopLeft":"5", "TopRight":"6", "BottomLeft":"7",
"BottomRight":"8", "Top":"1", "Bottom":"2", "Left":"3",
"Right":"4", "None":"0", "Book":"9",}
OPTIONS = {
"Url": "http://",
"Mode": 100,
"ManualNo": 0,
"DocPasswd": "",
"WebUserName": '',
"WebPasswd": '',
"PageMode": {'all': 0, 'range': 1, 'default': 0},
"StartPage": 1,
"EndPage": 1,
"Copies": lambda args: args.copies,
"MediaSize": lambda args: {
'auto': 0, 'default': 0,
"a4": 5, "a3": 6, "a5": 16, "b4": 12, "b5": 13,
"ltr": 1, "lgl": 2, "11x17": 3, "exec": 4, "com-10": 7,
"monarch": 8, "c5 env": 9, "b5 env": 10, "dl env": 11,
}.get(args.page_size.lower()),
"MediaType": 0, # TODO
"ManualFeed": 0,
"FitSize": lambda args: {'no': 0, 'yes': 1, 'default': 1}.get(args.expand),
#expand to mediasize
"DuplexType": lambda args:
{'book': 0, 'one-sided': 0, 'short-edge': 1,
'long-edge': 2}.get(args.duplex_type),
# NB: book => one-sided (sinon, ça peut merder)
"Sort": {'none': 0, 'finition': 1, 'default': 1},
#finition: pour tout ce qui a une finition
# TODO
"PunchPos": 0,
"StapleType": lambda args: STAPLE_POSITIONS['Book'] if args.duplex_type == 'book'
else STAPLE_POSITIONS[args.staple_position],
"BookType": lambda args: 0 if args.duplex_type == 'book' else 2,
"Annotation": 2,
"ColorMode": lambda args: {'yes': 2, 'no': 1}.get(args.colors),
"C_Render": 0, "C_RGB_Pro": 1, "C_CMYK_Pro": 4, "C_OUT_Pro": 1,
"C_GRAY_Pro": 1, "C_Matching": 0,
"SPOT_Color": 1,
"C_Pure_B": 1, "C_B_OVPrn": 1, "C_Bright": 100, "C_Gray_Com": 1,
"C_OVR_EFF": 1,
"WidePrn": 0,
"NupPrint": 0, "NupStart": 0,
"Resolution": 1,
"HalfToneTxt": 1, "HalfToneGrp": 1, "HalfToneImg": 1,
"AstIntensity": 2, "AstText": 0, "AstGrap": 1, "AstImag": 1,
"StoreBox": lambda args: int(args.test),
"BoxNo": 17,
"RGBDLName": "",
"CMYKDLName": "",
"OUTDLName": "",
"BOXName": lambda args: args.jobname + '_%d' % int(time.time()),
"Flag": "Exec_Data_Pdf",
"Dummy": lambda _: int(time.time()),
"Direct": 100,
}
def build_options(args):
opt = {}
for (k,v) in OPTIONS.iteritems():
if isinstance(v, types.FunctionType):
v = v(args)
if isinstance(v, dict):
v = v['default']
if not isinstance(v, file):
v = str(v)
opt[k] = v
return opt
def build_url(name):
""" Build url from a page name (see URIs) """
return (BASE_URL + URIs[name]) % {
'timestamp': int(time.time()),
}
def range_checker(a, b):
def cast(x):
try:
v = int(x)
except ValueError(err):
raise argparse.ArgumentTypeError(str(err))
if v not in xrange(a, b):
raise argparse.ArgumentTypeError("should be between %d and %d" % (a, b))
return v
return cast
def build_parser():
parser = argparse.ArgumentParser(
description="HTTP printing driver for irc3580, with compatibility mode.",
epilog="logs are sent to syslog (eg /var/log/canon_wrapper.log)",
prog='canon_wrapper',
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument('--jobname', help="job name as seen by the printer",
default="unamed job",
)
parser.add_argument('--copies', default=1,
help="number of copies",
type=range_checker(1,1000),
)
parser.add_argument('--colors', type=str, default='yes', const="yes",
nargs="?",
choices=["yes", "no"],
)
parser.add_argument('--expand', type=str, default='yes', const="yes",
nargs="?",
choices=["yes", "no"],
help="expand to page size",
)
parser.add_argument('--duplex-type', type=str, default='one-sided',
choices=["one-sided", "short-edge", "long-edge",
"book"],
)
parser.add_argument('--page-size', type=str, default='A4',
choices=["A3", "A4"],
help="page size",
)
parser.add_argument('--test', default=False, const=True,
action='store_const',
help="Don't really print, send to box folder",
)
parser.add_argument('--staple-position', default='None',
choices=STAPLE_POSITIONS.keys(),
help="Where to staple",
)
parser.add_argument('filename')
return parser
def do_print(args):
opt=build_options(args)
syslog('Options: %s' % repr(opt))
#syslog('Starting ghostscript compat, piped mode')
temppdf = tempfile.NamedTemporaryFile(suffix='.pdf')
syslog('Starting ghostscript compat to %s' % temppdf.name)
atexit.register(temppdf.close)
proc = subprocess.Popen(['/usr/bin/gs','-dCompatibilityLevel=1.2',
'-dBATCH','-dNOPAUSE','-sDEVICE=pdfwrite',
'-sOutputFile=' + temppdf.name,
args.filename])
# '-sOutputFile=%stdout%', '-q',
# args.filename], stdout=subprocess.PIPE)
ret = proc.wait()
syslog('ghostscript compat finished with ret=%d' % ret)
if ret != 0:
syslog('aborting.')
return ret
syslog('Getting cookie...')
cook = requests.get(build_url('root')).cookies
syslog('Sending pdf (%d bytes)...' % os.stat(temppdf.name).st_size)
temppdf.seek(0)
req = requests.post(build_url('do_print'), cookies=cook, data=opt,
files={'File': (args.jobname + '.pdf', temppdf)})
#files={'File': (args.jobname + '.pdf', proc.stdout)})
temppdf.close()
if "ms_err.gif" in req.text:
syslog("Printer side ERROR !")
return 42
syslog('Compatibilized pdf successfully sent. Continue tracking on the printer !')
return 0
if __name__ == '__main__':
parser = build_parser()
args = parser.parse_args()
if args:
try:
openlog('canon_wrapper[%s]' % args.jobname)
sys.exit(do_print(args))
except Exception as e:
syslog('Caught exception %s' % repr(e))
raise