Initial commit: Odoo 18.0-20251222 extra-addons
This commit is contained in:
158
report_qweb_pdf_watermark/models/report.py
Normal file
158
report_qweb_pdf_watermark/models/report.py
Normal file
@@ -0,0 +1,158 @@
|
||||
# © 2016 Therp BV <http://therp.nl>
|
||||
# Copyright 2023 Onestein - Anjeel Haria
|
||||
# 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
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
try:
|
||||
# we need this to be sure PIL has loaded PDF support
|
||||
from PIL import PdfImagePlugin # noqa: F401
|
||||
except ImportError:
|
||||
logger.error("ImportError: The PdfImagePlugin could not be imported")
|
||||
|
||||
try:
|
||||
try:
|
||||
from PyPDF2 import PdfReader, PdfWriter # pylint: disable=W0404
|
||||
from PyPDF2.errors import PdfReadError # pypdf >= 2.0
|
||||
except ImportError:
|
||||
from PyPDF2 import ( # pylint: disable=W0404
|
||||
PdfFileReader as PdfReader,
|
||||
)
|
||||
from PyPDF2 import (
|
||||
PdfFileWriter as PdfWriter,
|
||||
)
|
||||
from PyPDF2.utils import PdfReadError # pypdf < 2.0
|
||||
except ImportError:
|
||||
logger.warning("Can not import PyPDF2")
|
||||
|
||||
|
||||
class Report(models.Model):
|
||||
_inherit = "ir.actions.report"
|
||||
|
||||
use_company_watermark = fields.Boolean(
|
||||
default=False,
|
||||
help="Use the pdf watermark defined globally in the company settings.",
|
||||
)
|
||||
pdf_watermark = fields.Binary(
|
||||
"Watermark", help="Upload an pdf file to use as an watermark on this report."
|
||||
)
|
||||
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, report_ref, res_ids=None, data=None):
|
||||
if not self.env.context.get("res_ids"):
|
||||
self = self.with_context(res_ids=res_ids)
|
||||
return super()._render_qweb_pdf(report_ref, res_ids=res_ids, data=data)
|
||||
|
||||
@staticmethod
|
||||
def pdf_has_usable_pages(numpages):
|
||||
if numpages < 1:
|
||||
logger.error("Your watermark pdf does not contain any pages")
|
||||
return False
|
||||
if numpages > 1:
|
||||
logger.debug(
|
||||
"Your watermark pdf contains more than one page, "
|
||||
"all but the first one will be ignored"
|
||||
)
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def _run_wkhtmltopdf(
|
||||
self,
|
||||
bodies,
|
||||
report_ref=False,
|
||||
header=None,
|
||||
footer=None,
|
||||
landscape=False,
|
||||
specific_paperformat_args=None,
|
||||
set_viewport_size=False,
|
||||
):
|
||||
result = super()._run_wkhtmltopdf(
|
||||
bodies,
|
||||
report_ref=report_ref,
|
||||
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)
|
||||
report_sudo = self._get_report(report_ref)
|
||||
watermark = None
|
||||
if self.pdf_watermark or report_sudo.pdf_watermark:
|
||||
watermark = b64decode(self.pdf_watermark or report_sudo.pdf_watermark)
|
||||
elif (
|
||||
self.use_company_watermark or report_sudo.use_company_watermark
|
||||
) and self.env.company.pdf_watermark:
|
||||
watermark = b64decode(self.env.company.pdf_watermark)
|
||||
elif docids:
|
||||
watermark = safe_eval(
|
||||
self.pdf_watermark_expression
|
||||
or report_sudo.pdf_watermark_expression
|
||||
or "None",
|
||||
dict(
|
||||
env=self.env,
|
||||
docs=self.env[self.model or report_sudo.model].browse(docids),
|
||||
),
|
||||
)
|
||||
if watermark:
|
||||
watermark = b64decode(watermark)
|
||||
|
||||
if not watermark:
|
||||
return result
|
||||
|
||||
pdf = PdfWriter()
|
||||
pdf_watermark = None
|
||||
try:
|
||||
pdf_watermark = PdfReader(BytesIO(watermark))
|
||||
except (UnicodeDecodeError, 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 = PdfReader(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 not self.pdf_has_usable_pages(pdf_watermark.numPages):
|
||||
return result
|
||||
|
||||
for page in PdfReader(BytesIO(result)).pages:
|
||||
watermark_page = pdf.addBlankPage(
|
||||
page.mediaBox.getWidth(), page.mediaBox.getHeight()
|
||||
)
|
||||
# merge_page is >= 2.0, mergePage < 2.0
|
||||
merge_page = (
|
||||
getattr(watermark_page, "merge_page", None) or watermark_page.mergePage
|
||||
)
|
||||
merge_page(pdf_watermark.getPage(0))
|
||||
merge_page(page)
|
||||
|
||||
pdf_content = BytesIO()
|
||||
pdf.write(pdf_content)
|
||||
|
||||
return pdf_content.getvalue()
|
||||
Reference in New Issue
Block a user