Ticket #11: pkpgcounter-mediawork.patch

File pkpgcounter-mediawork.patch, 13.3 kB (added by jerome, 14 years ago)

Patch for pkpgcounter to extract additional informations from print jobs

  • bin/pkpgcounter

    diff --git a/bin/pkpgcounter b/bin/pkpgcounter
    index 4ffa10a..ae2d141 100755
    a b  
    8181                        grayscale pages from coloured pages but don't care 
    8282                        about ink usage per se. 
    8383 
     84  -m, --media 
     85                        Activate the media size, format and duplex detection / 
     86                        tracking code. 
     87 
    8488  -rRESOLUTION, --resolution=RESOLUTION 
    8589                        The resolution in DPI to use when checking ink usage. 
    8690                        Lower resolution is faster but less accurate. Default 
  • pkpgpdls/analyzer.py

    diff --git a/pkpgpdls/analyzer.py b/pkpgpdls/analyzer.py
    index 954aaad..e09f203 100644
    a b  
    33# pkpgcounter : a generic Page Description Language parser 
    44# 
    55# (c) 2003-2009 Jerome Alet <alet@librelogiciel.com> 
     6# Portions (c) 2009 Trever L. Adams <trever.adams@gmail.com> 
     7# 
    68# This program is free software: you can redistribute it and/or modify 
    79# it under the terms of the GNU General Public License as published by 
    810# the Free Software Foundation, either version 3 of the License, or 
     
    7173            self.closeFile() 
    7274        return size 
    7375 
     76    def getMediaFormat(self) : 
     77        """Returns the job's media/format.""" 
     78        result = None 
     79        self.openFile() 
     80        try : 
     81            try : 
     82                pdlhandler = self.detectPDLHandler() 
     83                result = pdlhandler.getMediaFormat() 
     84            except pdlparser.PDLParserError, msg : 
     85                raise pdlparser.PDLParserError, "Unsupported file format for %s (%s)" % (self.filename, msg) 
     86        finally : 
     87            self.closeFile() 
     88        return result 
     89 
    7490    def getInkCoverage(self, colorspace=None, resolution=None) : 
    7591        """Extracts the percents of ink coverage from the input file.""" 
    7692        result = None 
     
    211227                            action="store_true", 
    212228                            dest="debug", 
    213229                            help="Activate debug mode.") 
     230    parser.add_option("-m", "--media", 
     231                            action="store_true", 
     232                            dest="media", 
     233                            help="Activate the detection of various media/format options of the job.") 
    214234    parser.add_option("-c", "--colorspace", 
    215235                            dest="colorspace", 
    216236                            type="cichoice", 
     
    236256            for arg in arguments : 
    237257                try : 
    238258                    parser = PDLAnalyzer(arg, options) 
    239                     if not options.colorspace : 
     259                    if not options.colorspace and not options.media : 
    240260                        totalsize += parser.getJobSize() 
    241                     else : 
     261                    if options.colorspace : 
    242262                        (cspace, pages) = parser.getInkCoverage() 
     263                        if cspace == "BW" : 
     264                            cspace = "K" 
     265                        elif cspace == "GC" : 
     266                            cspace = ["GS", "CR"] 
    243267                        for page in pages : 
    244268                            lineparts = [] 
    245269                            for k in cspace : # NB : this way we preserve the order of the planes 
    246270                                try : 
    247                                     lineparts.append("%s : %s%%" % (k, ("%f" % page[k]).rjust(10))) 
     271                                    lineparts.append("%s: %s%%" % (k, ("%f" % page[k]).rjust(10))) 
     272                                except KeyError : 
     273                                    pass 
     274                            lines.append("  ".join(lineparts)) 
     275                    if options.media : 
     276                        (mspace, pages) = parser.getMediaFormat() 
     277                        if lines == [] : 
     278                            haveOutput = False 
     279                        else : 
     280                            haveOutput = True 
     281                        i = 0 
     282                        for page in pages : 
     283                            lineparts = [] 
     284                            for k in mspace : # NB : this way we preserve the order of the media format string 
     285                                try : 
     286                                    lineparts.append("%s: %s" % (k, ("%s" % page[k]).ljust(10))) 
    248287                                except KeyError : 
    249288                                    pass 
    250                             lines.append("      ".join(lineparts)) 
     289                            if haveOutput is False : 
     290                                lines.append("  ".join(lineparts)) 
     291                            else : 
     292                                lines[i] = lines[i] + '  ' + ''.join(lineparts) 
     293                            i = i + 1 
    251294                except (IOError, pdlparser.PDLParserError), msg : 
    252295                    sys.stderr.write("ERROR: %s\n" % msg) 
    253296                    sys.stderr.flush() 
    254297        except KeyboardInterrupt : 
    255298            sys.stderr.write("WARN: Aborted at user's request.\n") 
    256299            sys.stderr.flush() 
    257         if not options.colorspace : 
     300        if not options.colorspace and not options.media : 
    258301            sys.stdout.write("%i\n" % totalsize) 
    259302        else : 
    260303            sys.stdout.write("%s\n" % ("\n".join(lines))) 
  • pkpgpdls/inkcoverage.py

    diff --git a/pkpgpdls/inkcoverage.py b/pkpgpdls/inkcoverage.py
    index 900bf07..dc14be0 100644
    a b  
    7373    for (r, g, b) in img.getdata() : 
    7474        if not (r == g == b) : 
    7575            # optimize : if a single pixel is not gray the whole page is colored. 
    76             return { "G" : 0.0, "C" : 100.0 } 
    77     return { "G" : 100.0, "C" : 0.0 } 
     76            return { "GS" : 0.0, "CR" : 100.0 } 
     77    return { "GS" : 100.0, "CR" : 0.0 } 
    7878 
    7979def getPercentBW(img, nbpix) : 
    8080    """Extracts the percents of Black from a picture, once converted to gray levels.""" 
    8181    if img.mode != "L" : 
    8282        img = img.convert("L") 
    83     return { "B" : 100.0 - getPercent(img, nbpix)["L"] } 
     83    return { "K" : 100.0 - getPercent(img, nbpix)["L"] } 
    8484 
    8585def getPercentRGB(img, nbpix) : 
    8686    """Extracts the percents of Red, Green, Blue from a picture, once converted to RGB.""" 
  • pkpgpdls/postscript.py

    diff --git a/pkpgpdls/postscript.py b/pkpgpdls/postscript.py
    index 71b12ca..8fc984b 100644
    a b  
    33# pkpgcounter : a generic Page Description Language parser 
    44# 
    55# (c) 2003-2009 Jerome Alet <alet@librelogiciel.com> 
     6# (c) 2009 Trever L. Adams <trever.adams@gmail.com> 
     7# 
    68# This program is free software: you can redistribute it and/or modify 
    79# it under the terms of the GNU General Public License as published by 
    810# the Free Software Foundation, either version 3 of the License, or 
     
    2325 
    2426import sys 
    2527import os 
     28import re 
    2629 
    2730import pdlparser 
    2831import inkcoverage 
    2932 
     33findmediatype = re.compile(".*/MediaType [(]?([^)]*).*") 
     34findmediasize = re.compile(".*/PageSize \[?([\d.]*) ([\d.]*)\]?.*") 
     35findduplexoff = re.compile(r".*/Duplex false.*") 
     36findduplexon = re.compile(r".*/Duplex true.*") 
     37 
     38# Any zeros below indicate that the exact postscript size is unknown 
     39# Below are some papers that have multiple names. Don't use the Alias(es). 
     40# Cannocal              Alias 
     41# Leder                 11x17 
     42# Statement             half letter 
     43PostScriptPaperSizes = \ 
     44                ("A0", 2384, 3370), \ 
     45                ("A1", 1684, 2384), \ 
     46                ("A2", 1191, 1684), \ 
     47                ("A3", 842, 1191), \ 
     48                ("A4", 595, 842), \ 
     49                ("A5", 420, 595), \ 
     50                ("A6", 297, 420), \ 
     51                ("A7", 210, 297), \ 
     52                ("A8", 148, 210), \ 
     53                ("A9", 105, 148), \ 
     54                ("A10", 73, 105), \ 
     55                ("ArchA", 648, 864), \ 
     56                ("ArchB", 864, 1296), \ 
     57                ("ArchC", 1296, 1728), \ 
     58                ("ArchD", 1728, 2592), \ 
     59                ("ArchE", 2592, 3456), \ 
     60                ("B0", 2835, 4008), \ 
     61                ("B1", 2004, 2835), \ 
     62                ("B2", 1417, 2004), \ 
     63                ("B3", 1001, 1417), \ 
     64                ("B4", 709, 1001), \ 
     65                ("B5", 499, 709), \ 
     66                ("B6", 354, 499), \ 
     67                ("C0", 2599, 3677), \ 
     68                ("C1", 1837, 2599), \ 
     69                ("C2", 1298, 1837), \ 
     70                ("C3", 918, 1298), \ 
     71                ("C4", 649, 918), \ 
     72                ("C5", 459, 649), \ 
     73                ("C6", 323, 459), \ 
     74                ("COM10Envelope", 0, 0), \ 
     75                ("DL Envelope", 312, 624), \ 
     76                ("Envelope #9", 279, 639), \ 
     77                ("Envelope #10", 297, 684), \ 
     78                ("Envelope #11", 324, 747), \ 
     79                ("Envelope #12", 288, 792), \ 
     80                ("Envelope #14", 360, 828), \ 
     81                ("Executive", 540, 720), \ 
     82                ("Foolscap", 612, 936), \ 
     83                ("JDoublePostcard", 0, 0), \ 
     84                ("JIS16K", 0, 0), \ 
     85                ("JIS8K", 0, 0), \ 
     86                ("JISB0", 0, 0), \ 
     87                ("JISB1", 0, 0), \ 
     88                ("JISB2", 0, 0), \ 
     89                ("JISB3", 0, 0), \ 
     90                ("JISB4", 0, 0), \ 
     91                ("JISB5", 0, 0), \ 
     92                ("JISB6", 0, 0), \ 
     93                ("JISExec", 0, 0), \ 
     94                ("JPostcard", 0, 0), \ 
     95                ("Ledger", 792, 1224), \ 
     96                ("Legal", 612, 1008), \ 
     97                ("Letter", 612, 792), \ 
     98                ("MonarchEnvelope", 279, 540), \ 
     99                ("Statement", 396, 612)  
     100 
    30101class Parser(pdlparser.PDLParser) : 
    31102    """A parser for PostScript documents.""" 
    32103    totiffcommands = [ 'gs -sDEVICE=tiff24nc -dPARANOIDSAFER -dNOPAUSE -dBATCH -dQUIET -r"%(dpi)i" -sOutputFile="%(outfname)s" "%(infname)s"' ] 
     
    77148            if number > self.pages[pagenum]["copies"] : 
    78149                self.pages[pagenum]["copies"] = number 
    79150 
     151    def getpapersize(self, x, y) : 
     152        for tempsize in PostScriptPaperSizes : 
     153            if (float(x) == float(tempsize[1])) and (float(y) == float(tempsize[2])) : 
     154                return tempsize[0] 
     155 
    80156    def natively(self) : 
    81157        """Count pages in a DSC compliant PostScript document.""" 
    82158        pagecount = 0 
     
    87163        prescribe = False # Kyocera's Prescribe commands 
    88164        acrobatmarker = False 
    89165        pagescomment = None 
     166        duplexmode= "N" 
     167        mediasizelabel = "Letter" 
     168        mediatypelabel = "Plain" 
    90169        for line in self.infile : 
    91170            line = line.strip() 
    92171            parts = line.split() 
     
    145224                if proceed and not notinteger : 
    146225                    pagecount += 1 
    147226                    self.pages[pagecount] = { "copies" : self.pages[pagecount-1]["copies"] } 
     227                self.pages[pagecount]["duplex"] = duplexmode 
     228                self.pages[pagecount]["mediatype"] = mediatypelabel 
     229                self.pages[pagecount]["mediasize"] = mediasizelabel 
     230            elif findduplexon.search(line) : 
     231                self.pages[pagecount]["duplex"] = "Y" 
     232                duplexmode=self.pages[pagecount]["duplex"] 
     233            elif findduplexoff.search(line) : 
     234                self.pages[pagecount]["duplex"] = "N" 
     235                duplexmode=self.pages[pagecount]["duplex"] 
     236            elif findmediatype.search(line) : 
     237                mediatype = findmediatype.search(line) 
     238                self.pages[pagecount]["mediatype"] = mediatype.group(1) 
     239                mediatypelabel = self.pages[pagecount]["mediatype"] 
     240            elif findmediasize.search(line) : 
     241                mediasize = findmediasize.search(line) 
     242                try : 
     243                    self.pages[pagecount]["mediasize"] = self.getpapersize(min(mediasize.group(1), mediasize.group(2)), max(mediasize.group(1), mediasize.group(2))) 
     244                    mediasizelabel = self.pages[pagecount]["mediasize"] 
     245                except : 
     246                    pass 
    148247            elif (not prescribe) \ 
    149248               and (parts[:3] == [r"%%BeginResource:", "procset", "pdf"]) \ 
    150249               and not acrobatmarker : 
     
    169268            self.logdebug("%s * page #%s" % (copies, pnum)) 
    170269 
    171270        self.logdebug("Internal parser said : %s pages" % pagecount) 
    172         return (pagecount, notrust) 
     271        return (pagecount, notrust, self.pages) 
    173272 
    174273    def getJobSize(self) : 
    175274        """Count pages in PostScript document.""" 
    176275        self.copies = 1 
    177         (nbpages, notrust) = self.natively() 
     276        (nbpages, notrust, pages) = self.natively() 
    178277        newnbpages = nbpages 
    179278        if notrust or not nbpages : 
    180279            try : 
     
    182281            except pdlparser.PDLParserError, msg : 
    183282                self.logdebug(msg) 
    184283        return max(nbpages, newnbpages) 
     284 
     285    def getMediaFormat(self) : 
     286        """Discover media fomats/sizes in PostScript document.""" 
     287        result = [] 
     288        self.copies = 1 
     289        (nbpages, notrust, pages) = self.natively() 
     290        for k in pages : 
     291            if k > 0 : 
     292                result.append({"MT" : pages[k]["mediatype"], 
     293                               "MS" : pages[k]["mediasize"], 
     294                               "DU" : pages[k]["duplex"], 
     295                              }) 
     296        return ((["MT", "MS", "DU"]), result)