Changeset 1575
- Timestamp:
- 06/28/04 23:20:32 (20 years ago)
- Location:
- pykota/trunk
- Files:
-
- 6 modified
Legend:
- Unmodified
- Added
- Removed
-
pykota/trunk/conf/pykota.conf.sample
r1517 r1575 284 284 # pkpgcounter is a command line tool which is 285 285 # part of PyKota and which can handle both 286 # DSC compliant PostScript documents and PCL5287 # documents. More file formats will be added286 # DSC compliant PostScript, PCL5, PCL6 (aka PCLXL) 287 # and PDF documents. More file formats will be added 288 288 # in the future, as time permits. 289 289 # -
pykota/trunk/man/pkpgcounter.1
r1548 r1575 1 1 .TH PKPGCOUNTER "1" "April 2004" "C@LL - Conseil Internet & Logiciels Libres" "User Commands" 2 2 .SH NAME 3 pkpgcounter \- PyKota script to count pages in PostScript, PDF or PCLdocuments3 pkpgcounter \- PyKota script to count pages in PostScript, PDF, PCL5 and PCL6 documents 4 4 .SH SYNOPSIS 5 5 .B pkpgcounter … … 13 13 .PP 14 14 \fBpkpgcounter\fP is a convenience script provided by pykota that attempts 15 to count the number of pages in a PostScript, PDF or PCL document. This may be of use 15 to count the number of pages in a DSC compliant PostScript, PDF, PCL5 or 16 PCL6 (aka PCLXL) document. This may be of use 16 17 as an external accounter as defined in /etc/pykota/pykota.conf, since currently 17 18 \fBpkpgcounter\fP is the smarter software accounter included with PyKota. -
pykota/trunk/NEWS
r1573 r1575 22 22 PyKota NEWS : 23 23 24 - 1.19alpha28 : 25 26 - First working PCL6 (aka PCLXL) parser ! 27 Doesn't handle copies yet. 28 24 29 - 1.19alpha27 : 25 30 -
pykota/trunk/pykota/pdlanalyzer.py
r1574 r1575 22 22 # 23 23 # $Log$ 24 # Revision 1.19 2004/06/28 21:20:30 jalet 25 # PCLXL support now works ! 26 # 24 27 # Revision 1.18 2004/06/27 22:59:37 jalet 25 28 # More work on PCLXL parser … … 256 259 def __init__(self, infile) : 257 260 """Initialize PCLXL Analyzer.""" 258 raise PDLAnalyzerError, "PCLXL (aka PCL6) is not supported yet."261 # raise PDLAnalyzerError, "PCLXL (aka PCL6) is not supported yet." 259 262 self.infile = infile 260 263 self.islittleendian = None … … 268 271 endian = ord(line[0]) 269 272 if endian == 0x29 : 270 self.little endian()273 self.littleEndian() 271 274 elif endian == 0x28 : 272 self.bigendian() 275 self.bigEndian() 276 # elif endian == 0x27 : TODO : What can we do here ? 277 # 273 278 else : 274 279 raise PDLAnalyzerError, "No endianness marker 0x%02x at start !" % endian … … 276 281 raise PDLAnalyzerError, "This file doesn't seem to be PCLXL (aka PCL6)" 277 282 else : 278 self.tags = [ self.skipped ] * 256279 self.tags [0x27] = lambda: self.debug("%08x : ASCII Binding" % self.infile.tell())280 self.tags[0x28] = self.bigendian281 self.tags[0x29] = self.littleendian282 283 self.tags[0x 41] = lambda: self.debug("%08x : BeginSession" % self.infile.tell())284 self.tags[0x 42] = lambda: self.debug("%08x : EndSession" % self.infile.tell())283 # Initialize table of tags 284 self.tags = [ 0 ] * 256 285 286 # GhostScript's sources tell us that HP printers 287 # only accept little endianness, but we can handle both. 288 self.tags[0x28] = self.bigEndian # BigEndian 289 self.tags[0x29] = self.littleEndian # LittleEndian 285 290 286 291 self.tags[0x43] = self.beginPage # BeginPage 287 self.tags[0x44] = self.endPage # EndPage 288 289 self.tags[0x47] = lambda: self.debug("%08x : Comment" % self.infile.tell()) 290 self.tags[0x48] = lambda: self.debug("%08x : OpenDataSource" % self.infile.tell()) 291 self.tags[0x49] = lambda: self.debug("%08x : CloseDataSource" % self.infile.tell()) 292 293 self.tags[0xc0] = lambda: self.debug("%08x : ubyte" % self.infile.tell()) or 1 # ubyte 294 self.tags[0xc1] = lambda: self.debug("%08x : uint16" % self.infile.tell()) or 2 # uint16 295 self.tags[0xc2] = lambda: self.debug("%08x : uint32" % self.infile.tell()) or 4 # uint32 296 self.tags[0xc3] = lambda: self.debug("%08x : sint16" % self.infile.tell()) or 2 # sint16 297 self.tags[0xc4] = lambda: self.debug("%08x : sint32" % self.infile.tell()) or 4 # sint32 298 self.tags[0xc5] = lambda: self.debug("%08x : real32" % self.infile.tell()) or 4 # real32 292 293 self.tags[0xc0] = 1 # ubyte 294 self.tags[0xc1] = 2 # uint16 295 self.tags[0xc2] = 4 # uint32 296 self.tags[0xc3] = 2 # sint16 297 self.tags[0xc4] = 4 # sint32 298 self.tags[0xc5] = 4 # real32 299 299 300 300 self.tags[0xc8] = self.array_8 # ubyte_array … … 305 305 self.tags[0xcd] = self.array_32 # real32_array 306 306 307 self.tags[0xd0] = lambda: self.debug("%08x : ubyte_xy" % self.infile.tell()) or2 # ubyte_xy308 self.tags[0xd1] = lambda: self.debug("%08x : uint16_xy" % self.infile.tell()) or4 # uint16_xy309 self.tags[0xd2] = lambda: self.debug("%08x : uint32_xy" % self.infile.tell()) or8 # uint32_xy310 self.tags[0xd3] = lambda: self.debug("%08x : sint16_xy" % self.infile.tell()) or4 # sint16_xy311 self.tags[0xd4] = lambda: self.debug("%08x : sint32_xy" % self.infile.tell()) or8 # sint32_xy312 self.tags[0xd5] = lambda: self.debug("%08x : real32_xy" % self.infile.tell()) or8 # real32_xy313 314 self.tags[0x d0] = lambda: self.debug("%08x : ubyte_box" % self.infile.tell()) or4 # ubyte_box315 self.tags[0x d1] = lambda: self.debug("%08x : uint16_box" % self.infile.tell()) or8 # uint16_box316 self.tags[0x d2] = lambda: self.debug("%08x : uint32_box" % self.infile.tell()) or16 # uint32_box317 self.tags[0x d3] = lambda: self.debug("%08x : sint16_box" % self.infile.tell()) or8 # sint16_box318 self.tags[0x d4] = lambda: self.debug("%08x : sint32_box" % self.infile.tell()) or16 # sint32_box319 self.tags[0x d5] = lambda: self.debug("%08x : real32_box" % self.infile.tell()) or16 # real32_box320 321 self.tags[0xf8] = lambda: self.debug("%08x : attr_ubyte" % self.infile.tell()) or1 # attr_ubyte322 self.tags[0xf9] = lambda: self.debug("%08x : attr_uint16" % self.infile.tell()) or2 # attr_uint16307 self.tags[0xd0] = 2 # ubyte_xy 308 self.tags[0xd1] = 4 # uint16_xy 309 self.tags[0xd2] = 8 # uint32_xy 310 self.tags[0xd3] = 4 # sint16_xy 311 self.tags[0xd4] = 8 # sint32_xy 312 self.tags[0xd5] = 8 # real32_xy 313 314 self.tags[0xe0] = 4 # ubyte_box 315 self.tags[0xe1] = 8 # uint16_box 316 self.tags[0xe2] = 16 # uint32_box 317 self.tags[0xe3] = 8 # sint16_box 318 self.tags[0xe4] = 16 # sint32_box 319 self.tags[0xe5] = 16 # real32_box 320 321 self.tags[0xf8] = 1 # attr_ubyte 322 self.tags[0xf9] = 2 # attr_uint16 323 323 324 324 self.tags[0xfa] = self.embeddedData # dataLength 325 325 self.tags[0xfb] = self.embeddedDataSmall # dataLengthByte 326 326 327 def debug(self, msg) :328 """Outputs a debug message on stderr."""329 sys.stderr.write("%s\n" % msg)330 sys.stderr.flush()331 332 def skipped(self) :333 """Skips a byte."""334 self.debug("%08x : skip" % self.infile.tell())335 336 327 def beginPage(self) : 337 328 """Indicates the beginning of a new page.""" 338 329 self.pagecount += 1 339 self.debug("%08x : beginPage (%i)" % (self.infile.tell(), self.pagecount)) 340 341 def endPage(self) : 342 """Indicates the end of a page.""" 343 self.debug("%08x : endPage (%i)" % (self.infile.tell(), self.pagecount)) 330 return 0 344 331 345 332 def handleArray(self, itemsize) : 346 333 """Handles arrays.""" 347 pos = self.infile.tell() 348 datatype = self.infile.read(1) 349 self.debug("%08x : Array of datatype 0x%02x" % (pos, ord(datatype))) 350 length = self.tags[ord(datatype)]() 334 datatype = self.minfile[self.pos] 335 self.pos += 1 336 length = self.tags[ord(datatype)] 351 337 if length is None : 352 self.debug("Bogus array length at %s" % pos) 353 else : 354 sarraysize = self.infile.read(length) 355 if self.islittleendian : 356 fmt = "<" 357 else : 358 fmt = ">" 359 if length == 1 : 360 fmt += "B" 361 elif length == 2 : 362 fmt += "H" 363 elif length == 4 : 364 fmt += "I" 365 else : 366 raise PDLAnalyzerError, "Error on array size at %s" % self.infile.tell() 367 arraysize = struct.unpack(fmt, sarraysize)[0] 368 self.debug("itemsize %s * size %s = %s" % (itemsize, arraysize, itemsize*arraysize)) 369 return arraysize * itemsize 338 raise PDLAnalyzerError, "Error on array length at %s" % self.pos 339 elif callable(length) : 340 length = length() 341 pos = self.pos 342 posl = pos + length 343 sarraysize = self.minfile[pos:posl] 344 self.pos = posl 345 if self.islittleendian : 346 fmt = "<" 347 else : 348 fmt = ">" 349 if length == 1 : 350 fmt += "B" 351 elif length == 2 : 352 fmt += "H" 353 elif length == 4 : 354 fmt += "I" 355 else : 356 raise PDLAnalyzerError, "Error on array size at %s" % self.pos 357 arraysize = struct.unpack(fmt, sarraysize)[0] 358 return arraysize * itemsize 370 359 371 360 def array_8(self) : 372 361 """Handles byte arrays.""" 373 self.debug("%08x : array_8" % self.infile.tell())374 362 return self.handleArray(1) 375 363 376 364 def array_16(self) : 377 365 """Handles byte arrays.""" 378 self.debug("%08x : array_16" % self.infile.tell())379 366 return self.handleArray(2) 380 367 381 368 def array_32(self) : 382 369 """Handles byte arrays.""" 383 self.debug("%08x : array_32" % self.infile.tell())384 370 return self.handleArray(4) 385 371 386 372 def embeddedDataSmall(self) : 387 373 """Handle small amounts of data.""" 388 self.debug("%08x : small_datablock" % self.infile.tell()) 389 pos = self.infile.tell() 390 val = ord(self.infile.read(1)) 391 self.debug("%08x : Small datablock length : 0x%02x" % (self.infile.tell()-1, val)) 392 return val 374 length = ord(self.minfile[self.pos]) 375 self.pos += 1 376 return length 393 377 394 378 def embeddedData(self) : 395 379 """Handle normal amounts of data.""" 396 self.debug("%08x : large_datablock" % self.infile.tell())397 380 if self.islittleendian : 398 381 fmt = "<I" 399 382 else : 400 383 fmt = ">I" 401 pos = self.infile.tell() 402 data = self.infile.read(4) 403 val = struct.unpack(fmt, data)[0] 404 if val & 0xff000000 : # tries to detect possible errors when we missed an indianness tag maybe 405 if fmt == "<I" : 406 fmt = ">I" 407 else : 408 fmt = "<I" 409 val = struct.unpack(fmt, data)[0] 410 self.debug("%08x : Large datablock length : 0x%08x" % (self.infile.tell()-4, val)) 411 self.debug("Endian : %i" % self.islittleendian) 412 self.debug("Data read : %s" % str(["0x%02x" % ord(x) for x in data])) 413 return val 414 415 def littleendian(self) : 384 pos = self.pos 385 pos4 = pos + 4 386 data = self.minfile[pos:pos4] 387 self.pos = pos4 388 return struct.unpack(fmt, data)[0] 389 390 def littleEndian(self) : 416 391 """Toggles to little endianness.""" 417 self.debug("%08x : littleendian" % self.infile.tell())418 392 self.islittleendian = 1 # little endian 419 420 def bigendian(self) : 393 return 0 394 395 def bigEndian(self) : 421 396 """Toggles to big endianness.""" 422 self.debug("%08x : bigendian" % self.infile.tell())423 397 self.islittleendian = 0 # big endian 398 return 0 424 399 425 400 def getJobSize(self) : 426 401 """Counts pages in a PCLXL (PCL6) document.""" 402 infileno = self.infile.fileno() 403 self.minfile = mmap.mmap(infileno, os.fstat(infileno).st_size, access=mmap.ACCESS_READ) 427 404 self.pagecount = 0 428 while 1 : 429 char = self.infile.read(1) 430 if not char : 431 break 432 index = ord(char) 433 length = self.tags[index]() 434 if length : 435 self.infile.read(length) 405 self.pos = self.infile.tell() 406 try : 407 while 1 : 408 char = self.minfile[self.pos] 409 self.pos += 1 410 length = self.tags[ord(char)] 411 if not length : 412 continue 413 if callable(length) : 414 length = length() 415 self.pos += length 416 except IndexError : # EOF ? 417 self.minfile.close() # reached EOF 436 418 return self.pagecount 437 419 -
pykota/trunk/pykota/version.py
r1570 r1575 22 22 # 23 23 24 __version__ = "1.19alpha2 7_unofficial"24 __version__ = "1.19alpha28_unofficial" 25 25 26 26 __doc__ = """PyKota : a complete Printing Quota Solution for CUPS and LPRng.""" -
pykota/trunk/README
r1571 r1575 71 71 This is completely configurable. 72 72 73 - Supports PostScript, PDF and PCL5 printers natively 74 for software accounting methods. More formats to come. 73 - Supports DSC compliant PostScript, PDF, PCL5 and 74 PCLXL (aka PCL6) printers natively for software 75 accounting methods. More formats to come. 75 76 76 77 Quota systems : … … 226 227 227 228 On Intel i386 architecture, and for performance reasons if you 228 print in PCL format, it is strongly suggested that you install229 the Python accelerator Psyco, available at :229 print in PCL5 or PCL6 format, it is strongly suggested that you 230 install the Python accelerator Psyco, available at : 230 231 231 232 http://psyco.sourceforge.net … … 238 239 on Psyco's website. 239 240 240 Installing Psyco is not mandatory, but it woud speedup PCL parsing241 Installing Psyco is not mandatory, but it woud speedup PCL5 parsing 241 242 by almost 3 times. PostScript and PDF parsing can also benefit, 242 243 but in an almost unnoticeable manner since this part of the code 243 is already optimal. For PCL this is a completely different matter,244 is already optimal. For PCL5 this is a completely different matter, 244 245 and if you install Psyco you will never regret it ! 246 Same remark applies for PCL6 (aka PCLXL) but performance improvement 247 is yet to be tested (it is high anyway). 245 248 246 249 You may also benefit from having the following tools installed to