OCA reporting engine fork for dev and update.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

110 lines
3.9 KiB

  1. # © 2016 Therp BV <http://therp.nl>
  2. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  3. from base64 import b64decode
  4. from logging import getLogger
  5. from PIL import Image
  6. from io import BytesIO
  7. try:
  8. # we need this to be sure PIL has loaded PDF support
  9. from PIL import PdfImagePlugin # noqa: F401
  10. except ImportError:
  11. pass
  12. from odoo import api, models, fields, tools
  13. logger = getLogger(__name__)
  14. try:
  15. from PyPDF2 import PdfFileWriter, PdfFileReader # pylint: disable=W0404
  16. from PyPDF2.utils import PdfReadError # pylint: disable=W0404
  17. except ImportError:
  18. logger.debug('Can not import PyPDF2')
  19. class Report(models.Model):
  20. _inherit = 'ir.actions.report'
  21. pdf_watermark = fields.Binary('Watermark')
  22. pdf_watermark_expression = fields.Char(
  23. 'Watermark expression', help='An expression yielding the base64 '
  24. 'encoded data to be used as watermark. \n'
  25. 'You have access to variables `env` and `docs`')
  26. @api.multi
  27. def render_qweb_pdf(self, res_ids=None, data=None):
  28. if not self.env.context.get('res_ids'):
  29. return super(
  30. Report, self.with_context(res_ids=res_ids)
  31. ).render_qweb_pdf(res_ids=res_ids, data=data)
  32. return super(Report, self).render_qweb_pdf(res_ids=res_ids, data=data)
  33. @api.model
  34. def _run_wkhtmltopdf(self, bodies, header=None, footer=None,
  35. landscape=False, specific_paperformat_args=None,
  36. set_viewport_size=False):
  37. result = super(Report, self)._run_wkhtmltopdf(
  38. bodies, header=header, footer=footer, landscape=landscape,
  39. specific_paperformat_args=specific_paperformat_args,
  40. set_viewport_size=set_viewport_size)
  41. docids = self.env.context.get('res_ids', False)
  42. watermark = None
  43. if self.pdf_watermark:
  44. watermark = b64decode(self.pdf_watermark)
  45. elif docids:
  46. watermark = tools.safe_eval(
  47. self.pdf_watermark_expression or 'None',
  48. dict(env=self.env, docs=self.env[self.model].browse(docids)),
  49. )
  50. if watermark:
  51. watermark = b64decode(watermark)
  52. if not watermark:
  53. return result
  54. pdf = PdfFileWriter()
  55. pdf_watermark = None
  56. try:
  57. pdf_watermark = PdfFileReader(BytesIO(watermark))
  58. except PdfReadError:
  59. # let's see if we can convert this with pillow
  60. try:
  61. Image.init()
  62. image = Image.open(BytesIO(watermark))
  63. pdf_buffer = BytesIO()
  64. if image.mode != 'RGB':
  65. image = image.convert('RGB')
  66. resolution = image.info.get(
  67. 'dpi', self.paperformat_id.dpi or 90
  68. )
  69. if isinstance(resolution, tuple):
  70. resolution = resolution[0]
  71. image.save(pdf_buffer, 'pdf', resolution=resolution)
  72. pdf_watermark = PdfFileReader(pdf_buffer)
  73. except:
  74. logger.exception('Failed to load watermark')
  75. if not pdf_watermark:
  76. logger.error(
  77. 'No usable watermark found, got %s...', watermark[:100]
  78. )
  79. return result
  80. if pdf_watermark.numPages < 1:
  81. logger.error('Your watermark pdf does not contain any pages')
  82. return result
  83. if pdf_watermark.numPages > 1:
  84. logger.debug('Your watermark pdf contains more than one page, '
  85. 'all but the first one will be ignored')
  86. for page in PdfFileReader(BytesIO(result)).pages:
  87. watermark_page = pdf.addBlankPage(
  88. page.mediaBox.getWidth(), page.mediaBox.getHeight()
  89. )
  90. watermark_page.mergePage(pdf_watermark.getPage(0))
  91. watermark_page.mergePage(page)
  92. pdf_content = BytesIO()
  93. pdf.write(pdf_content)
  94. return pdf_content.getvalue()