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.
122 lines
4.0 KiB
122 lines
4.0 KiB
# © 2016 Therp BV <http://therp.nl>
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|
from base64 import b64decode
|
|
from io import BytesIO
|
|
from logging import getLogger
|
|
|
|
from PIL import Image
|
|
|
|
from odoo import api, fields, models
|
|
from odoo.tools.safe_eval import safe_eval
|
|
|
|
try:
|
|
# we need this to be sure PIL has loaded PDF support
|
|
from PIL import PdfImagePlugin # noqa: F401
|
|
except ImportError:
|
|
pass
|
|
|
|
logger = getLogger(__name__)
|
|
|
|
try:
|
|
from PyPDF2 import PdfFileReader, PdfFileWriter # pylint: disable=W0404
|
|
from PyPDF2.utils import PdfReadError # pylint: disable=W0404
|
|
except ImportError:
|
|
logger.debug("Can not import PyPDF2")
|
|
|
|
|
|
class Report(models.Model):
|
|
_inherit = "ir.actions.report"
|
|
|
|
pdf_watermark = fields.Binary("Watermark")
|
|
pdf_watermark_expression = fields.Char(
|
|
"Watermark expression",
|
|
help="An expression yielding the base64 "
|
|
"encoded data to be used as watermark. \n"
|
|
"You have access to variables `env` and `docs`",
|
|
)
|
|
|
|
def _render_qweb_pdf(self, res_ids=None, data=None):
|
|
if not self.env.context.get("res_ids"):
|
|
return super(Report, self.with_context(res_ids=res_ids))._render_qweb_pdf(
|
|
res_ids=res_ids, data=data
|
|
)
|
|
return super(Report, self)._render_qweb_pdf(res_ids=res_ids, data=data)
|
|
|
|
@api.model
|
|
def _run_wkhtmltopdf(
|
|
self,
|
|
bodies,
|
|
header=None,
|
|
footer=None,
|
|
landscape=False,
|
|
specific_paperformat_args=None,
|
|
set_viewport_size=False,
|
|
):
|
|
result = super(Report, self)._run_wkhtmltopdf(
|
|
bodies,
|
|
header=header,
|
|
footer=footer,
|
|
landscape=landscape,
|
|
specific_paperformat_args=specific_paperformat_args,
|
|
set_viewport_size=set_viewport_size,
|
|
)
|
|
|
|
docids = self.env.context.get("res_ids", False)
|
|
watermark = None
|
|
if self.pdf_watermark:
|
|
watermark = b64decode(self.pdf_watermark)
|
|
elif docids:
|
|
watermark = safe_eval(
|
|
self.pdf_watermark_expression or "None",
|
|
dict(env=self.env, docs=self.env[self.model].browse(docids)),
|
|
)
|
|
if watermark:
|
|
watermark = b64decode(watermark)
|
|
|
|
if not watermark:
|
|
return result
|
|
|
|
pdf = PdfFileWriter()
|
|
pdf_watermark = None
|
|
try:
|
|
pdf_watermark = PdfFileReader(BytesIO(watermark))
|
|
except PdfReadError:
|
|
# let's see if we can convert this with pillow
|
|
try:
|
|
Image.init()
|
|
image = Image.open(BytesIO(watermark))
|
|
pdf_buffer = BytesIO()
|
|
if image.mode != "RGB":
|
|
image = image.convert("RGB")
|
|
resolution = image.info.get("dpi", self.paperformat_id.dpi or 90)
|
|
if isinstance(resolution, tuple):
|
|
resolution = resolution[0]
|
|
image.save(pdf_buffer, "pdf", resolution=resolution)
|
|
pdf_watermark = PdfFileReader(pdf_buffer)
|
|
except Exception as e:
|
|
logger.exception("Failed to load watermark", e)
|
|
|
|
if not pdf_watermark:
|
|
logger.error("No usable watermark found, got %s...", watermark[:100])
|
|
return result
|
|
|
|
if pdf_watermark.numPages < 1:
|
|
logger.error("Your watermark pdf does not contain any pages")
|
|
return result
|
|
if pdf_watermark.numPages > 1:
|
|
logger.debug(
|
|
"Your watermark pdf contains more than one page, "
|
|
"all but the first one will be ignored"
|
|
)
|
|
|
|
for page in PdfFileReader(BytesIO(result)).pages:
|
|
watermark_page = pdf.addBlankPage(
|
|
page.mediaBox.getWidth(), page.mediaBox.getHeight()
|
|
)
|
|
watermark_page.mergePage(pdf_watermark.getPage(0))
|
|
watermark_page.mergePage(page)
|
|
|
|
pdf_content = BytesIO()
|
|
pdf.write(pdf_content)
|
|
|
|
return pdf_content.getvalue()
|