#! /usr/bin/env python # -*- coding: utf-8 -*- # # PyKota : Print Quotas for CUPS # # (c) 2003-2013 Jerome Alet # 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 . # # $Id: pkbanner 3561 2013-01-04 22:34:24Z jerome $ # # """A banner generator for PyKota""" import sys import os import time import cStringIO import subprocess try : from reportlab.pdfgen import canvas import reportlab.lib from reportlab.lib.units import cm except ImportError : hasRL = False else : hasRL = True try : import PIL.Image except ImportError : hasPIL = False else : hasPIL = True import pykota.appinit from pykota.utils import run from pykota.commandline import PyKotaOptionParser, \ checkandset_pagesize, \ checkandset_savetoner from pykota.pdfutils import getPageSize from pykota.errors import PyKotaToolError from pykota.tool import Tool from pykota import version class PyKotaBanner(Tool) : """A class for pkbanner.""" def getVar(self, varname) : """Extracts a variable from the environment and returns its value or 'Unknown' in the current locale.""" return os.environ.get(varname) or _("Unknown") def printVar(self, canvas, x, y, label, value, size, savetoner) : """Outputs a variable onto the PDF canvas. Returns the number of points to substract to current Y coordinate. """ canvas.saveState() canvas.setFont("Helvetica-Bold", size) (r, g, b) = [ color + (savetoner * (1.0 - color)) for color in (0, 0, 0) ] # Black * savetoner canvas.setFillColorRGB(r, g, b) message = "%s :" % _(label) canvas.drawRightString(x, y, message) canvas.setFont("Courier-Bold", size) (r, g, b) = [ color + (savetoner * (1.0 - color)) for color in (1, 0, 0) ] # Red * savetoner canvas.setFillColorRGB(r, g, b) canvas.drawString(x + 0.5*cm, y, value) canvas.restoreState() return (size + 4) def genPDF(self, pagesize, logo, url, text, savetoner) : """Generates the banner in PDF format, return the PDF document as a string.""" document = cStringIO.StringIO() c = canvas.Canvas(document, pagesize=pagesize, pageCompression=1) c.setAuthor(self.effectiveUserName) c.setTitle(_("PyKota generated Banner")) c.setSubject(_("This is a print banner generated with PyKota")) xcenter = pagesize[0] / 2.0 ycenter = pagesize[1] / 2.0 ypos = pagesize[1] - (2 * cm) if logo : try : imglogo = PIL.Image.open(logo) except : self.printInfo("Unable to open image %s" % logo, "warn") else : (width, height) = imglogo.size multi = float(width) / (8 * cm) width = float(width) / multi height = float(height) / multi xpos = xcenter - (width / 2.0) ypos -= height c.drawImage(logo, xpos, ypos, width, height) # New top xpos = pagesize[0] / 5.0 ypos -= (1 * cm) + 20 printername = self.getVar("PYKOTAPRINTERNAME") username = self.getVar("PYKOTAUSERNAME") accountbanner = self.config.getAccountBanner(printername) # Outputs the username ypos -= self.printVar(c, xcenter, ypos, _("Username"), username, 20, savetoner) # Text if text : ypos -= self.printVar(c, xcenter, ypos, _("More Info"), text, 20, savetoner) # Printer and Job Id job = "%s - %s" % (printername, self.getVar("PYKOTAJOBID")) ypos -= self.printVar(c, xcenter, ypos, _("Job"), job, 14, savetoner) # Current date (TODO : at the time the banner was printed ! Change this to job's submission date) datetime = time.strftime("%c", time.localtime()).decode(self.charset, "replace") ypos -= self.printVar(c, xcenter, ypos, _("Date"), datetime, 14, savetoner) # Result of the print job action = self.getVar("PYKOTAACTION") if action == "ALLOW" : action = _("Allowed") elif action == "DENY" : action = _("Denied") elif action == "WARN" : action = _("Allowed with Warning") elif action == "PROBLEM" : # should never occur action = _("Problem") elif action == "CANCEL" : # should never occur action = _("Cancelled") ypos -= self.printVar(c, xcenter, ypos, _("Result"), action, 14, savetoner) # skip some space ypos -= 20 # Outputs title and filename # We put them at x=0.25*pagewidth so that the line is long enough to hold them title = self.getVar("PYKOTATITLE") ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Title"), title, 10, savetoner) filename = self.getVar("PYKOTAFILENAME") ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Filename"), filename, 10, savetoner) # skip some space ypos -= 20 # Now outputs the user's account balance or page counter ypos -= self.printVar(c, xcenter, ypos, _("Pages printed so far on %s") % printername, self.getVar("PYKOTAPAGECOUNTER"), 14, savetoner) limitby = self.getVar("PYKOTALIMITBY") if limitby == "balance" : ypos -= self.printVar(c, xcenter, ypos, _("Account balance"), self.getVar("PYKOTABALANCE"), 14, savetoner) elif limitby == "quota" : ypos -= self.printVar(c, xcenter, ypos, _("Soft Limit"), self.getVar("PYKOTASOFTLIMIT"), 14, savetoner) ypos -= self.printVar(c, xcenter, ypos, _("Hard Limit"), self.getVar("PYKOTAHARDLIMIT"), 14, savetoner) ypos -= self.printVar(c, xcenter, ypos, _("Date Limit"), self.getVar("PYKOTADATELIMIT"), 14, savetoner) else : if limitby == "noquota" : msg = _("No Limit") elif limitby == "nochange" : msg = _("No Accounting") elif limitby == "noprint" : msg = _("Forbidden") else : msg = _("Unknown") ypos -= self.printVar(c, xcenter, ypos, _("Printing Mode"), msg, 14, savetoner) # URL if url : c.saveState() c.setFont("Courier-Bold", 16) (r, g, b) = [ color + (savetoner * (1.0 - color)) for color in (0, 0, 1) ] # Blue * savetoner c.setFillColorRGB(r, g, b) c.drawCentredString(xcenter, 2 * cm, url) c.restoreState() c.showPage() c.save() return document.getvalue() def main(self, arguments, options) : """Generates a banner.""" if not hasRL : raise PyKotaToolError, "The ReportLab module is missing. Download it from http://www.reportlab.org" if not hasPIL : raise PyKotaToolError, "The Python Imaging Library is missing. Download it from http://www.pythonware.com/downloads" self.logdebug("Generating the banner in PDF format...") doc = self.genPDF(getPageSize(options.pagesize), options.logo.strip().encode(sys.getfilesystemencoding(), "replace"), options.url.strip(), " ".join(arguments).strip(), options.savetoner / 100.0) self.logdebug("Converting the banner to PostScript...") command = "gs -q -dNOPAUSE -dBATCH -dPARANOIDSAFER -sDEVICE=pswrite -sOutputFile=- -" subpr = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) try : (out, err) = subpr.communicate(doc) except OSError, msg : raise PyKotaToolError, _("Impossible to execute '%(command)s'") % locals() status = subpr.wait() if os.WIFEXITED(status) : status = os.WEXITSTATUS(status) self.logdebug("PDF to PostScript converter exit code is %s" % str(status)) sys.stdout.write(out) sys.stdout.flush() self.logdebug("Banner completed.") return status if __name__ == "__main__" : # TODO : --papertray : to print banners on a different paper (colored for example) parser = PyKotaOptionParser(description=_("Banner generator for PyKota.")) parser.add_option("-l", "--logo", dest="logo", default=u"/usr/share/pykota/logos/pykota.jpeg", help=_("The image to use as a logo. The logo will be drawn at the center top of the page. The default logo is %default.")) parser.add_option("-p", "--pagesize", type="string", action="callback", callback=checkandset_pagesize, dest="pagesize", default=u"A4", help=_("Set the size of the page. Most well known page sizes are recognized, like 'A4' or 'Letter' to name a few. The default page size is %default.")) parser.add_option("-s", "--savetoner", type="float", action="callback", callback=checkandset_savetoner, dest="savetoner", default=0.0, help=_("Set the text luminosity to this percent. This can be used to save toner. The default value is %default, which means that no toner saving will be done.")) parser.add_option("-u", "--url", dest="url", default=u"http://www.pykota.com", help=_("Set the url to write at the bottom of the banner page. The default url is %default.")) parser.add_example('--logo="" --savetoner=75', _("This would generate a banner in the default page size, with no logo, and text luminosity would be increased by 75%.")) run(parser, PyKotaBanner)