pdfpattern.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. __doc__="""helper for importing pdf structures into a ReportLab generated document
  2. """
  3. from reportlab.pdfbase.pdfdoc import format, PDFObject, pdfdocEnc
  4. from reportlab.lib.utils import strTypes
  5. def _patternSequenceCheck(pattern_sequence):
  6. allowedTypes = strTypes if isinstance(strTypes, tuple) else (strTypes,)
  7. allowedTypes = allowedTypes + (PDFObject,PDFPatternIf)
  8. for x in pattern_sequence:
  9. if not isinstance(x,allowedTypes):
  10. if len(x)!=1:
  11. raise ValueError("sequence elts must be strings/bytes/PDFPatternIfs or singletons containing strings: "+ascii(x))
  12. if not isinstance(x[0],strTypes):
  13. raise ValueError("Singletons must contain strings/bytes or PDFObject instances only: "+ascii(x[0]))
  14. class PDFPattern(PDFObject):
  15. __RefOnly__ = 1
  16. def __init__(self, pattern_sequence, **keywordargs):
  17. """
  18. Description of a kind of PDF object using a pattern.
  19. Pattern sequence should contain strings, singletons of form [string] or
  20. PDFPatternIf objects.
  21. Strings are literal strings to be used in the object.
  22. Singletons are names of keyword arguments to include.
  23. PDFpatternIf objects allow some conditionality.
  24. Keyword arguments can be non-instances which are substituted directly in string conversion,
  25. or they can be object instances in which case they should be pdfdoc.* style
  26. objects with a x.format(doc) method.
  27. Keyword arguments may be set on initialization or subsequently using __setitem__, before format.
  28. "constant object" instances can also be inserted in the patterns.
  29. """
  30. _patternSequenceCheck(pattern_sequence)
  31. self.pattern = pattern_sequence
  32. self.arguments = keywordargs
  33. def __setitem__(self, item, value):
  34. self.arguments[item] = value
  35. def __getitem__(self, item):
  36. return self.arguments[item]
  37. def eval(self,L):
  38. arguments = self.arguments
  39. document = self.__document
  40. for x in L:
  41. if isinstance(x,strTypes):
  42. yield pdfdocEnc(x)
  43. elif isinstance(x,PDFObject):
  44. yield x.format(document)
  45. elif isinstance(x,PDFPatternIf):
  46. result = list(self.eval(x.cond))
  47. cond = result and result[0]
  48. for z in self.eval(x.thenPart if cond else x.elsePart):
  49. yield z
  50. else:
  51. name = x[0]
  52. value = arguments.get(name, None)
  53. if value is None:
  54. raise ValueError("%s value not defined" % ascii(name))
  55. if isinstance(value,PDFObject):
  56. yield format(value,document)
  57. elif isinstance(value,strTypes):
  58. yield pdfdocEnc(value)
  59. else:
  60. yield pdfdocEnc(str(value))
  61. def format(self, document):
  62. self.__document = document
  63. try:
  64. return b"".join(self.eval(self.pattern))
  65. finally:
  66. del self.__document
  67. def clone(self):
  68. c = object.__new__(self.__class__)
  69. c.pattern = self.pattern
  70. c.arguments = self.arguments
  71. return c
  72. class PDFPatternIf(object):
  73. '''cond will be evaluated as [cond] in PDFpattern eval.
  74. It should evaluate to a list with value 0/1 etc etc.
  75. thenPart is a list to be evaluated if the cond evaulates true,
  76. elsePart is the false sequence.
  77. '''
  78. def __init__(self,cond,thenPart=[],elsePart=[]):
  79. if not isinstance(cond,list): cond = [cond]
  80. for x in cond, thenPart, elsePart:
  81. _patternSequenceCheck(x)
  82. self.cond = cond
  83. self.thenPart = thenPart
  84. self.elsePart = elsePart