Holger Brunn
8 years ago
committed by
Pedro M. Baeza
12 changed files with 278 additions and 0 deletions
-
7.travis.yml
-
62report_qweb_pdf_watermark/README.rst
-
4report_qweb_pdf_watermark/__init__.py
-
18report_qweb_pdf_watermark/__openerp__.py
-
30report_qweb_pdf_watermark/demo/report.xml
-
5report_qweb_pdf_watermark/models/__init__.py
-
14report_qweb_pdf_watermark/models/ir_actions_report_xml.py
-
87report_qweb_pdf_watermark/models/report.py
-
BINreport_qweb_pdf_watermark/static/description/icon.png
-
4report_qweb_pdf_watermark/tests/__init__.py
-
32report_qweb_pdf_watermark/tests/test_report_qweb_pdf_watermark.py
-
15report_qweb_pdf_watermark/views/ir_actions_report_xml.xml
@ -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() |
After Width: 128 | Height: 128 | 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> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue