report_qweb_pdf_watermark (#86)
parent
a3dbd504fa
commit
aeb5c9a149
|
@ -0,0 +1,62 @@
|
||||||
|
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
|
||||||
|
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||||
|
:alt: License: AGPL-3
|
||||||
|
|
||||||
|
=============
|
||||||
|
Pdf watermark
|
||||||
|
=============
|
||||||
|
|
||||||
|
This module was written to add watermarks (backgrounds) to PDF reports.
|
||||||
|
|
||||||
|
This is necessary because of the way wkhtmltopdf handles headers and footers, in the current versions if quite impossible to have a background for the complete page.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
|
||||||
|
To use this module, you need to:
|
||||||
|
|
||||||
|
#. go to your report
|
||||||
|
#. select a PDF or image to use as watermark. Note that resolutions and size must match, otherwise you'll have funny results
|
||||||
|
#. advanced users (members of group technical settings) can also fill in an expression that returns the data (base64 encoded) to be used as watermark
|
||||||
|
|
||||||
|
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
|
||||||
|
:alt: Try me on Runbot
|
||||||
|
:target: https://runbot.odoo-community.org/runbot/143/8.0
|
||||||
|
|
||||||
|
Bug Tracker
|
||||||
|
===========
|
||||||
|
|
||||||
|
Bugs are tracked on `GitHub Issues
|
||||||
|
<https://github.com/OCA/reporting-engine/issues>`_. In case of trouble, please
|
||||||
|
check there if your issue has already been reported. If you spotted it first,
|
||||||
|
help us smashing it by providing a detailed and welcomed feedback.
|
||||||
|
|
||||||
|
Credits
|
||||||
|
=======
|
||||||
|
|
||||||
|
Images
|
||||||
|
------
|
||||||
|
|
||||||
|
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
|
||||||
|
|
||||||
|
Contributors
|
||||||
|
------------
|
||||||
|
|
||||||
|
* Holger Brunn <hbrunn@therp.nl>
|
||||||
|
|
||||||
|
Do not contact contributors directly about help with questions or problems concerning this addon, but use the `community mailing list <mailto:community@mail.odoo.com>`_ or the `appropriate specialized mailinglist <https://odoo-community.org/groups>`_ for help, and the bug tracker linked in `Bug Tracker`_ above for technical issues.
|
||||||
|
|
||||||
|
Maintainer
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. image:: https://odoo-community.org/logo.png
|
||||||
|
:alt: Odoo Community Association
|
||||||
|
:target: https://odoo-community.org
|
||||||
|
|
||||||
|
This module is maintained by the OCA.
|
||||||
|
|
||||||
|
OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||||
|
mission is to support the collaborative development of Odoo features and
|
||||||
|
promote its widespread use.
|
||||||
|
|
||||||
|
To contribute to this module, please visit https://odoo-community.org.
|
|
@ -0,0 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# © 2016 Therp BV <http://therp.nl>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
from . import models
|
|
@ -0,0 +1,18 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# © 2016 Therp BV <http://therp.nl>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
{
|
||||||
|
"name": "Pdf watermark",
|
||||||
|
"version": "9.0.1.0.0",
|
||||||
|
"author": "Therp BV,Odoo Community Association (OCA)",
|
||||||
|
"license": "AGPL-3",
|
||||||
|
"category": "Reporting",
|
||||||
|
"summary": "Add watermarks to your QWEB PDF reports",
|
||||||
|
"depends": [
|
||||||
|
'report',
|
||||||
|
],
|
||||||
|
"data": [
|
||||||
|
"demo/report.xml",
|
||||||
|
"views/ir_actions_report_xml.xml",
|
||||||
|
],
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<openerp>
|
||||||
|
<data>
|
||||||
|
<report
|
||||||
|
id="demo_report"
|
||||||
|
string="Demo report"
|
||||||
|
model="res.users"
|
||||||
|
report_type="qweb-pdf"
|
||||||
|
name="report_qweb_pdf_watermark.demo_report_view"
|
||||||
|
file="report_qweb_pdf_watermark.demo_report_view"
|
||||||
|
paperformat="report.paperformat_euro"
|
||||||
|
/>
|
||||||
|
<record id="demo_report" model="ir.actions.report.xml">
|
||||||
|
<field name="pdf_watermark_expression">docs[:1].company_id.logo</field>
|
||||||
|
</record>
|
||||||
|
<template id="demo_report_view">
|
||||||
|
<t t-call="report.html_container">
|
||||||
|
<t t-call="report.external_layout">
|
||||||
|
<div class="page">
|
||||||
|
<ul>
|
||||||
|
<li t-foreach="docs" t-as="doc">
|
||||||
|
<t t-esc="doc.name" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
</data>
|
||||||
|
</openerp>
|
|
@ -0,0 +1,5 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# © 2016 Therp BV <http://therp.nl>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
from . import ir_actions_report_xml
|
||||||
|
from . import report
|
|
@ -0,0 +1,14 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# © 2016 Therp BV <http://therp.nl>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
from openerp import fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class IrActionsReportXml(models.Model):
|
||||||
|
_inherit = 'ir.actions.report.xml'
|
||||||
|
|
||||||
|
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`')
|
|
@ -0,0 +1,87 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# © 2016 Therp BV <http://therp.nl>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
from base64 import b64decode
|
||||||
|
from logging import getLogger
|
||||||
|
from pyPdf import PdfFileWriter, PdfFileReader
|
||||||
|
from pyPdf.utils import PdfReadError
|
||||||
|
from PIL import Image
|
||||||
|
from StringIO import StringIO
|
||||||
|
from openerp import api, models, tools
|
||||||
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Report(models.Model):
|
||||||
|
_inherit = 'report'
|
||||||
|
|
||||||
|
@api.v7
|
||||||
|
def get_pdf(
|
||||||
|
self, cr, uid, ids, report_name, html=None, data=None, context=None
|
||||||
|
):
|
||||||
|
# pylint: disable=R8110
|
||||||
|
# this override cannot be done in v8 api
|
||||||
|
result = super(Report, self).get_pdf(
|
||||||
|
cr, uid, ids, report_name, html=html, data=data,
|
||||||
|
context=context
|
||||||
|
)
|
||||||
|
report = self._get_report_from_name(cr, uid, report_name)
|
||||||
|
watermark = None
|
||||||
|
if report.pdf_watermark:
|
||||||
|
watermark = b64decode(report.pdf_watermark)
|
||||||
|
else:
|
||||||
|
env = api.Environment(cr, uid, context)
|
||||||
|
watermark = tools.safe_eval(
|
||||||
|
report.pdf_watermark_expression or 'None',
|
||||||
|
dict(env=env, docs=env[report.model].browse(ids)),
|
||||||
|
)
|
||||||
|
if watermark:
|
||||||
|
watermark = b64decode(watermark)
|
||||||
|
|
||||||
|
if not watermark:
|
||||||
|
return result
|
||||||
|
|
||||||
|
pdf = PdfFileWriter()
|
||||||
|
pdf_watermark = None
|
||||||
|
try:
|
||||||
|
pdf_watermark = PdfFileReader(StringIO(watermark))
|
||||||
|
except PdfReadError:
|
||||||
|
# let's see if we can convert this with pillow
|
||||||
|
try:
|
||||||
|
image = Image.open(StringIO(watermark))
|
||||||
|
pdf_buffer = StringIO()
|
||||||
|
if image.mode != 'RGB':
|
||||||
|
image = image.convert('RGB')
|
||||||
|
resolution = image.info.get(
|
||||||
|
'dpi', report.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:
|
||||||
|
logger.exception('Failed to load watermark')
|
||||||
|
|
||||||
|
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(StringIO(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 = StringIO()
|
||||||
|
pdf.write(pdf_content)
|
||||||
|
|
||||||
|
return pdf_content.getvalue()
|
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
|
@ -0,0 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# © 2016 Therp BV <http://therp.nl>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
from . import test_report_qweb_pdf_watermark
|
|
@ -0,0 +1,32 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# © 2016 Therp BV <http://therp.nl>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
from openerp.tests.common import TransactionCase
|
||||||
|
|
||||||
|
|
||||||
|
class TestReportQwebPdfWatermark(TransactionCase):
|
||||||
|
def test_report_qweb_pdf_watermark(self):
|
||||||
|
# with our image, we have three
|
||||||
|
self._test_report_images(3)
|
||||||
|
|
||||||
|
self.env.ref('report_qweb_pdf_watermark.demo_report').write({
|
||||||
|
'pdf_watermark_expression': False,
|
||||||
|
})
|
||||||
|
# without, we have two
|
||||||
|
self._test_report_images(2)
|
||||||
|
|
||||||
|
self.env.ref('report_qweb_pdf_watermark.demo_report').write({
|
||||||
|
'pdf_watermark': self.env.user.company_id.logo,
|
||||||
|
})
|
||||||
|
# and now we should have three again
|
||||||
|
self._test_report_images(3)
|
||||||
|
|
||||||
|
def _test_report_images(self, number):
|
||||||
|
pdf = self.registry['report'].get_pdf(
|
||||||
|
self.cr,
|
||||||
|
self.uid,
|
||||||
|
self.env['res.users'].search([]).ids,
|
||||||
|
'report_qweb_pdf_watermark.demo_report_view',
|
||||||
|
context={}
|
||||||
|
)
|
||||||
|
self.assertEqual(pdf.count('/Subtype /Image'), number)
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<openerp>
|
||||||
|
<data>
|
||||||
|
<record id="act_report_xml_view" model="ir.ui.view">
|
||||||
|
<field name="model">ir.actions.report.xml</field>
|
||||||
|
<field name="inherit_id" ref="base.act_report_xml_view" />
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<field name="attachment" position="after">
|
||||||
|
<field name="pdf_watermark" attrs="{'invisible': [('report_type', '!=', 'qweb-pdf')]}" />
|
||||||
|
<field name="pdf_watermark_expression" attrs="{'invisible': [('report_type', '!=', 'qweb-pdf')]}" groups="base.group_no_one" />
|
||||||
|
</field>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</openerp>
|
Loading…
Reference in New Issue