mirror of https://github.com/muk-it/muk_base
MuK IT GmbH
5 years ago
3 changed files with 390 additions and 390 deletions
-
2muk_thumbnails/__manifest__.py
-
356muk_thumbnails/doc/index.rst
-
422muk_thumbnails/service/thumbnail.py
@ -1,178 +1,178 @@ |
|||||
============== |
|
||||
MuK Thumbnails |
|
||||
============== |
|
||||
|
|
||||
Technical module to provide some utility features and libraries that can be used |
|
||||
in other applications. This module has no direct effect on the running system. |
|
||||
|
|
||||
Requirements |
|
||||
============= |
|
||||
|
|
||||
Unoconv |
|
||||
------------- |
|
||||
|
|
||||
Universal Office Converter (unoconv) is a command line tool to convert any |
|
||||
document format that LibreOffice can import to any document format that |
|
||||
LibreOffice can export. It makes use of the LibreOffice's UNO bindings for |
|
||||
non-interactive conversion of documents. |
|
||||
|
|
||||
To install unoconv please follow the instructions (`here <https://github.com/dagwieers/unoconv>`_). |
|
||||
|
|
||||
Make sure that unoconv can be executed from the console and the conversion |
|
||||
is done correctly. |
|
||||
|
|
||||
To set an individual path for the LibreOffice installation, the config |
|
||||
variable ``uno_path`` can be set accordingly in the Odoo config. |
|
||||
|
|
||||
Under Windows you should rename the ``unoconv`` file to ``unoconv.py`` and set |
|
||||
the corresponding path for the ``uno_path`` variable. Since it does not work |
|
||||
reliably with the environment variable ``UNO_PATH``. |
|
||||
|
|
||||
FFmpeg |
|
||||
------------- |
|
||||
|
|
||||
FFmpeg is a complete, cross-platform solution to record, convert and stream audio and video. |
|
||||
|
|
||||
To install FFmpeg please follow the instructions (`here <https://www.ffmpeg.org/download.html>`_). |
|
||||
|
|
||||
Ghostscript |
|
||||
------------- |
|
||||
|
|
||||
Ghostscript is a suite of software based on an interpreter for Adobe Systems PostScript and |
|
||||
Portable Document Format (PDF) page description languages. Its main purposes are the |
|
||||
rasterization or rendering of such page description language files, for the display or printing |
|
||||
of document pages, and the conversion between PostScript and PDF files. |
|
||||
|
|
||||
To install Ghostscript please follow the instructions (`here <https://www.ghostscript.com/download.html>`_). |
|
||||
|
|
||||
ImageMagick |
|
||||
------------- |
|
||||
|
|
||||
ImageMagick can be used to create, edit, compose, or convert bitmap images. It can read and write |
|
||||
images in a variety of formats (over 200) including PNG, JPEG, GIF, HEIC, TIFF, DPX, EXR, WebP, |
|
||||
Postscript, PDF, and SVG. Use ImageMagick to resize, flip, mirror, rotate, distort, shear and |
|
||||
transform images, adjust image colors, apply various special effects, or draw text, lines, polygons, |
|
||||
ellipses and Bezier curves. |
|
||||
|
|
||||
To install ImageMagick please follow the instructions (`here <https://www.imagemagick.org/script/download.php>`_). |
|
||||
|
|
||||
Wand |
|
||||
------------- |
|
||||
|
|
||||
Wand is a ctypes-based simple ImageMagick binding for Python. It is used to interact with ImageMagick via a Python interface. |
|
||||
|
|
||||
To install Wand please follow the instructions (`here <http://docs.wand-py.org/en/0.4.1/guide/install.html>`_). |
|
||||
|
|
||||
Imageio |
|
||||
------------- |
|
||||
|
|
||||
Imageio is a Python library that provides an easy interface to read and write a wide range of image data, including animated images, volumetric data, and scientific formats. |
|
||||
|
|
||||
To install Imageio please follow the instructions (`here <https://pypi.org/project/imageio/>`_). |
|
||||
|
|
||||
MoviePy |
|
||||
------------- |
|
||||
|
|
||||
MoviePy is a Python module for video editing, which can be used for basic operations (like cuts, concatenations, title insertions), video compositing (a.k.a. non-linear editing), video processing, or to create advanced effects. It can read and write the most common video formats, including GIF. |
|
||||
|
|
||||
To install MoviePy please follow the instructions (`here <https://zulko.github.io/moviepy/install.html>`_). |
|
||||
|
|
||||
Installation |
|
||||
============ |
|
||||
|
|
||||
To install this module, you need to: |
|
||||
|
|
||||
Download the module and add it to your Odoo addons folder. Afterward, log on to |
|
||||
your Odoo server and go to the Apps menu. Trigger the debug mode and update the |
|
||||
list by clicking on the "Update Apps List" link. Now install the module by |
|
||||
clicking on the install button. |
|
||||
|
|
||||
Another way to install this module is via the package management for Python |
|
||||
(`PyPI <https://pypi.org/project/pip/>`_). |
|
||||
|
|
||||
To install our modules using the package manager make sure |
|
||||
`odoo-autodiscover <https://pypi.org/project/odoo-autodiscover/>`_ is installed |
|
||||
correctly. Then open a console and install the module by entering the following |
|
||||
command: |
|
||||
|
|
||||
``pip install --extra-index-url https://nexus.mukit.at/repository/odoo/simple <module>`` |
|
||||
|
|
||||
The module name consists of the Odoo version and the module name, where |
|
||||
underscores are replaced by a dash. |
|
||||
|
|
||||
**Module:** |
|
||||
|
|
||||
``odoo<version>-addon-<module_name>`` |
|
||||
|
|
||||
**Example:** |
|
||||
|
|
||||
``sudo -H pip3 install --extra-index-url https://nexus.mukit.at/repository/odoo/simple odoo11-addon-muk-utils`` |
|
||||
|
|
||||
Once the installation has been successfully completed, the app is already in the |
|
||||
correct folder. Log on to your Odoo server and go to the Apps menu. Trigger the |
|
||||
debug mode and update the list by clicking on the "Update Apps List" link. Now |
|
||||
install the module by clicking on the install button. |
|
||||
|
|
||||
The biggest advantage of this variant is that you can now also update the app |
|
||||
using the "pip" command. To do this, enter the following command in your console: |
|
||||
|
|
||||
``pip install --upgrade --extra-index-url https://nexus.mukit.at/repository/odoo/simple <module>`` |
|
||||
|
|
||||
When the process is finished, restart your server and update the application in |
|
||||
Odoo. The steps are the same as for the installation only the button has changed |
|
||||
from "Install" to "Upgrade". |
|
||||
|
|
||||
You can also view available Apps directly in our `repository <https://nexus.mukit.at/#browse/browse:odoo>`_ |
|
||||
and find a more detailed installation guide on our `website <https://mukit.at/page/open-source>`_. |
|
||||
|
|
||||
For modules licensed under OPL-1, you will receive access data when you purchase |
|
||||
the module. If the modules were not purchased directly from |
|
||||
`MuK IT <https://www.mukit.at/>`_ please contact our support (support@mukit.at) |
|
||||
with a confirmation of purchase to receive the corresponding access data. |
|
||||
|
|
||||
Upgrade |
|
||||
============ |
|
||||
|
|
||||
To upgrade this module, you need to: |
|
||||
|
|
||||
Download the module and add it to your Odoo addons folder. Restart the server |
|
||||
and log on to your Odoo server. Select the Apps menu and upgrade the module by |
|
||||
clicking on the upgrade button. |
|
||||
|
|
||||
If you installed the module using the "pip" command, you can also update the |
|
||||
module in the same way. Just type the following command into the console: |
|
||||
|
|
||||
``pip install --upgrade --extra-index-url https://nexus.mukit.at/repository/odoo/simple <module>`` |
|
||||
|
|
||||
When the process is finished, restart your server and update the application in |
|
||||
Odoo, just like you would normally. |
|
||||
|
|
||||
Configuration |
|
||||
============= |
|
||||
|
|
||||
No additional configuration is needed to use this module. |
|
||||
|
|
||||
Usage |
|
||||
============= |
|
||||
|
|
||||
This module has no direct visible effect on the system. It provide utility features. |
|
||||
|
|
||||
Credits |
|
||||
======= |
|
||||
|
|
||||
Contributors |
|
||||
------------ |
|
||||
|
|
||||
* Mathias Markl <mathias.markl@mukit.at> |
|
||||
|
|
||||
Author & Maintainer |
|
||||
------------------- |
|
||||
|
|
||||
This module is maintained by the `MuK IT GmbH <https://www.mukit.at/>`_. |
|
||||
|
|
||||
MuK IT is an Austrian company specialized in customizing and extending Odoo. |
|
||||
We develop custom solutions for your individual needs to help you focus on |
|
||||
your strength and expertise to grow your business. |
|
||||
|
|
||||
If you want to get in touch please contact us via mail |
|
||||
(sale@mukit.at) or visit our website (https://mukit.at). |
|
||||
|
============== |
||||
|
MuK Thumbnails |
||||
|
============== |
||||
|
|
||||
|
Technical module to provide some utility features and libraries that can be used |
||||
|
in other applications. This module has no direct effect on the running system. |
||||
|
|
||||
|
Requirements |
||||
|
============= |
||||
|
|
||||
|
Unoconv |
||||
|
------------- |
||||
|
|
||||
|
Universal Office Converter (unoconv) is a command line tool to convert any |
||||
|
document format that LibreOffice can import to any document format that |
||||
|
LibreOffice can export. It makes use of the LibreOffice's UNO bindings for |
||||
|
non-interactive conversion of documents. |
||||
|
|
||||
|
To install unoconv please follow the instructions (`here <https://github.com/dagwieers/unoconv>`_). |
||||
|
|
||||
|
Make sure that unoconv can be executed from the console and the conversion |
||||
|
is done correctly. |
||||
|
|
||||
|
To set an individual path for the LibreOffice installation, the config |
||||
|
variable ``uno_path`` can be set accordingly in the Odoo config. |
||||
|
|
||||
|
Under Windows you should rename the ``unoconv`` file to ``unoconv.py`` and set |
||||
|
the corresponding path for the ``uno_path`` variable. Since it does not work |
||||
|
reliably with the environment variable ``UNO_PATH``. |
||||
|
|
||||
|
FFmpeg |
||||
|
------------- |
||||
|
|
||||
|
FFmpeg is a complete, cross-platform solution to record, convert and stream audio and video. |
||||
|
|
||||
|
To install FFmpeg please follow the instructions (`here <https://www.ffmpeg.org/download.html>`_). |
||||
|
|
||||
|
Ghostscript |
||||
|
------------- |
||||
|
|
||||
|
Ghostscript is a suite of software based on an interpreter for Adobe Systems PostScript and |
||||
|
Portable Document Format (PDF) page description languages. Its main purposes are the |
||||
|
rasterization or rendering of such page description language files, for the display or printing |
||||
|
of document pages, and the conversion between PostScript and PDF files. |
||||
|
|
||||
|
To install Ghostscript please follow the instructions (`here <https://www.ghostscript.com/download.html>`_). |
||||
|
|
||||
|
ImageMagick |
||||
|
------------- |
||||
|
|
||||
|
ImageMagick can be used to create, edit, compose, or convert bitmap images. It can read and write |
||||
|
images in a variety of formats (over 200) including PNG, JPEG, GIF, HEIC, TIFF, DPX, EXR, WebP, |
||||
|
Postscript, PDF, and SVG. Use ImageMagick to resize, flip, mirror, rotate, distort, shear and |
||||
|
transform images, adjust image colors, apply various special effects, or draw text, lines, polygons, |
||||
|
ellipses and Bezier curves. |
||||
|
|
||||
|
To install ImageMagick please follow the instructions (`here <https://www.imagemagick.org/script/download.php>`_). |
||||
|
|
||||
|
Wand |
||||
|
------------- |
||||
|
|
||||
|
Wand is a ctypes-based simple ImageMagick binding for Python. It is used to interact with ImageMagick via a Python interface. |
||||
|
|
||||
|
To install Wand please follow the instructions (`here <http://docs.wand-py.org/en/0.4.1/guide/install.html>`_). |
||||
|
|
||||
|
Imageio |
||||
|
------------- |
||||
|
|
||||
|
Imageio is a Python library that provides an easy interface to read and write a wide range of image data, including animated images, volumetric data, and scientific formats. |
||||
|
|
||||
|
To install Imageio please follow the instructions (`here <https://pypi.org/project/imageio/>`_). |
||||
|
|
||||
|
MoviePy |
||||
|
------------- |
||||
|
|
||||
|
MoviePy is a Python module for video editing, which can be used for basic operations (like cuts, concatenations, title insertions), video compositing (a.k.a. non-linear editing), video processing, or to create advanced effects. It can read and write the most common video formats, including GIF. |
||||
|
|
||||
|
To install MoviePy please follow the instructions (`here <https://zulko.github.io/moviepy/install.html>`_). |
||||
|
|
||||
|
Installation |
||||
|
============ |
||||
|
|
||||
|
To install this module, you need to: |
||||
|
|
||||
|
Download the module and add it to your Odoo addons folder. Afterward, log on to |
||||
|
your Odoo server and go to the Apps menu. Trigger the debug mode and update the |
||||
|
list by clicking on the "Update Apps List" link. Now install the module by |
||||
|
clicking on the install button. |
||||
|
|
||||
|
Another way to install this module is via the package management for Python |
||||
|
(`PyPI <https://pypi.org/project/pip/>`_). |
||||
|
|
||||
|
To install our modules using the package manager make sure |
||||
|
`odoo-autodiscover <https://pypi.org/project/odoo-autodiscover/>`_ is installed |
||||
|
correctly. Then open a console and install the module by entering the following |
||||
|
command: |
||||
|
|
||||
|
``pip install --extra-index-url https://nexus.mukit.at/repository/odoo/simple <module>`` |
||||
|
|
||||
|
The module name consists of the Odoo version and the module name, where |
||||
|
underscores are replaced by a dash. |
||||
|
|
||||
|
**Module:** |
||||
|
|
||||
|
``odoo<version>-addon-<module_name>`` |
||||
|
|
||||
|
**Example:** |
||||
|
|
||||
|
``sudo -H pip3 install --extra-index-url https://nexus.mukit.at/repository/odoo/simple odoo11-addon-muk-utils`` |
||||
|
|
||||
|
Once the installation has been successfully completed, the app is already in the |
||||
|
correct folder. Log on to your Odoo server and go to the Apps menu. Trigger the |
||||
|
debug mode and update the list by clicking on the "Update Apps List" link. Now |
||||
|
install the module by clicking on the install button. |
||||
|
|
||||
|
The biggest advantage of this variant is that you can now also update the app |
||||
|
using the "pip" command. To do this, enter the following command in your console: |
||||
|
|
||||
|
``pip install --upgrade --extra-index-url https://nexus.mukit.at/repository/odoo/simple <module>`` |
||||
|
|
||||
|
When the process is finished, restart your server and update the application in |
||||
|
Odoo. The steps are the same as for the installation only the button has changed |
||||
|
from "Install" to "Upgrade". |
||||
|
|
||||
|
You can also view available Apps directly in our `repository <https://nexus.mukit.at/#browse/browse:odoo>`_ |
||||
|
and find a more detailed installation guide on our `website <https://mukit.at/page/open-source>`_. |
||||
|
|
||||
|
For modules licensed under OPL-1, you will receive access data when you purchase |
||||
|
the module. If the modules were not purchased directly from |
||||
|
`MuK IT <https://www.mukit.at/>`_ please contact our support (support@mukit.at) |
||||
|
with a confirmation of purchase to receive the corresponding access data. |
||||
|
|
||||
|
Upgrade |
||||
|
============ |
||||
|
|
||||
|
To upgrade this module, you need to: |
||||
|
|
||||
|
Download the module and add it to your Odoo addons folder. Restart the server |
||||
|
and log on to your Odoo server. Select the Apps menu and upgrade the module by |
||||
|
clicking on the upgrade button. |
||||
|
|
||||
|
If you installed the module using the "pip" command, you can also update the |
||||
|
module in the same way. Just type the following command into the console: |
||||
|
|
||||
|
``pip install --upgrade --extra-index-url https://nexus.mukit.at/repository/odoo/simple <module>`` |
||||
|
|
||||
|
When the process is finished, restart your server and update the application in |
||||
|
Odoo, just like you would normally. |
||||
|
|
||||
|
Configuration |
||||
|
============= |
||||
|
|
||||
|
No additional configuration is needed to use this module. |
||||
|
|
||||
|
Usage |
||||
|
============= |
||||
|
|
||||
|
This module has no direct visible effect on the system. It provide utility features. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Contributors |
||||
|
------------ |
||||
|
|
||||
|
* Mathias Markl <mathias.markl@mukit.at> |
||||
|
|
||||
|
Author & Maintainer |
||||
|
------------------- |
||||
|
|
||||
|
This module is maintained by the `MuK IT GmbH <https://www.mukit.at/>`_. |
||||
|
|
||||
|
MuK IT is an Austrian company specialized in customizing and extending Odoo. |
||||
|
We develop custom solutions for your individual needs to help you focus on |
||||
|
your strength and expertise to grow your business. |
||||
|
|
||||
|
If you want to get in touch please contact us via mail |
||||
|
(sale@mukit.at) or visit our website (https://mukit.at). |
@ -1,211 +1,211 @@ |
|||||
################################################################################### |
|
||||
# |
|
||||
# Copyright (C) 2018 MuK IT GmbH |
|
||||
# |
|
||||
# This program is free software: you can redistribute it and/or modify |
|
||||
# it under the terms of the GNU Affero General Public License as |
|
||||
# published by the Free Software Foundation, either version 3 of the |
|
||||
# License, or (at your option) any later version. |
|
||||
# |
|
||||
# This program is distributed in the hope that it will be useful, |
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
# GNU Affero General Public License for more details. |
|
||||
# |
|
||||
# You should have received a copy of the GNU Affero General Public License |
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
||||
# |
|
||||
################################################################################### |
|
||||
|
|
||||
import os |
|
||||
import io |
|
||||
import sys |
|
||||
import PyPDF2 |
|
||||
import base64 |
|
||||
import shutil |
|
||||
import urllib |
|
||||
import logging |
|
||||
import tempfile |
|
||||
import mimetypes |
|
||||
|
|
||||
from contextlib import closing |
|
||||
|
|
||||
from odoo.tools import config |
|
||||
from odoo.tools.mimetypes import guess_mimetype |
|
||||
|
|
||||
from odoo.addons.muk_utils.tools import utils_os |
|
||||
from odoo.addons.muk_converter.service import unoconv |
|
||||
|
|
||||
_logger = logging.getLogger(__name__) |
|
||||
|
|
||||
try: |
|
||||
from wand.image import Image |
|
||||
from wand.color import Color |
|
||||
except ImportError: |
|
||||
Image = False |
|
||||
Color = False |
|
||||
_logger.warn('Cannot `import wand`.') |
|
||||
|
|
||||
try: |
|
||||
import imageio |
|
||||
except ImportError: |
|
||||
imageio = False |
|
||||
_logger.warn('Cannot `import imageio`.') |
|
||||
|
|
||||
try: |
|
||||
from moviepy.editor import VideoFileClip |
|
||||
except ImportError: |
|
||||
VideoFileClip = False |
|
||||
_logger.warn('Cannot `import moviepy`.') |
|
||||
|
|
||||
FORMATS = [ |
|
||||
"png", "jpg", "jepg" |
|
||||
] |
|
||||
|
|
||||
VIDEO_IMPORTS = [ |
|
||||
"mp4", "mov", "wav", "avi", "mpg", "flv", "wmv", "webm" |
|
||||
] |
|
||||
|
|
||||
PDF_IMPORTS = [ |
|
||||
"pdf" |
|
||||
] |
|
||||
|
|
||||
WAND_IMPORTS = [ |
|
||||
"aai", "art", "arw", "avi", "avs", "bpg", "brf", "cals", "cgm", "cin", "cip", "cmyk", "cmyka", "svg", |
|
||||
"cr2", "crw", "cur", "cut", "dcm", "dcr", "dcx", "dds", "dib", "djvu", "dng", "dot", "dpx", "tim", |
|
||||
"emf", "epdf", "epi", "eps", "eps2", "eps3", "epsf", "epsi", "ept", "exr", "fax", "fig", "fits", |
|
||||
"fpx", "gplt", "gray", "graya", "hdr", "hdr", "heic", "hpgl", "hrz", "html", "ico", "info", "ttf", |
|
||||
"inline", "isobrl", "isobrl6", "jbig", "jng", "jp2", "jpt", "j2c", "j2k", "jxr", "json", "man", "bmp", |
|
||||
"mat", "miff", "mono", "mng", "m2v", "mpeg", "mpc", "mpr", "mrw", "msl", "mtv", "mvg", "nef", "yuv", |
|
||||
"orf", "otb", "p7", "palm", "pam", "clipboard", "pbm", "pcd", "pcds", "pcl", "pcx", "pdb", "jpe", |
|
||||
"pef", "pes", "pfa", "pfb", "pfm", "pgm", "picon", "pict", "pix", "png8", "png00", "png24", "tiff", |
|
||||
"png32", "png48", "png64", "pnm", "ppm", "ps", "ps2", "ps3", "psb", "psd", "ptif", "pwp", "rad", |
|
||||
"raf", "rgb", "rgba", "rgf", "rla", "rle", "sct", "sfw", "sgi", "shtml", "sid", " mrsid", "jpeg", |
|
||||
"sparse-color", "sun", "tga", "ubrl", "ubrl6", "uyvy", "vicar", "viff", "wbmp", "jpg", "png", "uil", |
|
||||
"wdp", "webp", "wmf", "wpg", "x", "xbm", "xcf", "xpm", "xwd", "x3f", "ycbcr", "ycbcra", "bmp3", "bmp2", |
|
||||
] |
|
||||
|
|
||||
def formats(): |
|
||||
return FORMATS |
|
||||
|
|
||||
def imports(): |
|
||||
return VIDEO_IMPORTS + PDF_IMPORTS + WAND_IMPORTS + unoconv.IMPORTS |
|
||||
|
|
||||
def create_thumbnail(binary, mimetype=None, filename=None, export="binary", format="png", page=0, frame=0, |
|
||||
animation=False, video_resize={'width': 256}, image_resize='256x256>', image_crop=None): |
|
||||
""" |
|
||||
Converts a thumbnail for a given file. |
|
||||
|
|
||||
:param binary: The binary value. |
|
||||
:param mimetype: The mimetype of the binary value. |
|
||||
:param filename: The filename of the binary value. |
|
||||
:param export: The output format (binary, file, base64). |
|
||||
:param format: Specify the output format for the document. |
|
||||
:param page: Specifies the page if the file has several pages, e.g. if it is a PDF file. |
|
||||
:param frame: Specifies the frame if the file has several frames, e.g. if it is a video file. |
|
||||
:param animation: In this case, the parameter frame specifies the number of frames. |
|
||||
:param video_resize: Specify to resize the output image. |
|
||||
:param image_resize: Specify to resize the output image. |
|
||||
:param image_crop: Specify to crop the output image. |
|
||||
:return: Returns the output depending on the given format. |
|
||||
:raises ValueError: The file extension could not be determined or the format is invalid. |
|
||||
""" |
|
||||
extension = utils_os.get_extension(binary, filename, mimetype) |
|
||||
if not extension: |
|
||||
raise ValueError("The file extension could not be determined.") |
|
||||
if format not in FORMATS: |
|
||||
raise ValueError("Invalid export format.") |
|
||||
if extension not in (VIDEO_IMPORTS + PDF_IMPORTS + WAND_IMPORTS + unoconv.IMPORTS): |
|
||||
raise ValueError("Invalid import format.") |
|
||||
if not imageio or not Image or not VideoFileClip: |
|
||||
raise ValueError("Some libraries couldn't be imported.") |
|
||||
image_data = None |
|
||||
image_extension = extension |
|
||||
if extension in WAND_IMPORTS: |
|
||||
image_data = binary |
|
||||
elif not image_data and (extension in PDF_IMPORTS or extension in unoconv.IMPORTS): |
|
||||
pdf_data = binary if extension in PDF_IMPORTS else None |
|
||||
if not pdf_data: |
|
||||
image_extension = "pdf" |
|
||||
pdf_data = unoconv.convert_binary(binary, mimetype, filename) |
|
||||
reader = PyPDF2.PdfFileReader(io.BytesIO(pdf_data)) |
|
||||
writer = PyPDF2.PdfFileWriter() |
|
||||
if reader.getNumPages() >= page: |
|
||||
writer.addPage(reader.getPage(page)) |
|
||||
else: |
|
||||
writer.addPage(reader.getPage(0)) |
|
||||
pdf_bytes = io.BytesIO() |
|
||||
writer.write(pdf_bytes) |
|
||||
image_data = pdf_bytes.getvalue() |
|
||||
if image_data: |
|
||||
with Image(blob=image_data, format=image_extension) as thumbnail: |
|
||||
thumbnail.format = format |
|
||||
if image_extension == "pdf": |
|
||||
thumbnail.background_color = Color('white') |
|
||||
thumbnail.alpha_channel = 'remove' |
|
||||
if image_resize: |
|
||||
thumbnail.transform(resize=image_resize) |
|
||||
if image_crop: |
|
||||
thumbnail.transform(crop=image_crop) |
|
||||
if export == 'file': |
|
||||
return io.BytesIO(thumbnail.make_blob()) |
|
||||
elif export == 'base64': |
|
||||
return base64.b64encode(thumbnail.make_blob()) |
|
||||
else: |
|
||||
return thumbnail.make_blob() |
|
||||
elif extension in VIDEO_IMPORTS: |
|
||||
tmp_dir = tempfile.mkdtemp() |
|
||||
try: |
|
||||
tmp_wpath = os.path.join(tmp_dir, "tmpfile.%s" % extension) |
|
||||
if os.name == 'nt': |
|
||||
tmp_wpath = tmp_wpath.replace("\\", "/") |
|
||||
with closing(open(tmp_wpath, 'wb')) as file: |
|
||||
file.write(binary) |
|
||||
clip = VideoFileClip(tmp_wpath) |
|
||||
try: |
|
||||
tmp_opath = os.path.join(tmp_dir, "output.%s" % format) |
|
||||
clip.resize(**video_resize) |
|
||||
if animation: |
|
||||
files = [] |
|
||||
current_frame = 0 |
|
||||
while clip.duration > current_frame and current_frame < frame: |
|
||||
filename = os.path.join(tmp_dir, "output_%s.png" % frame) |
|
||||
clip.save_frame(filename, t=frame) |
|
||||
files.append(filename) |
|
||||
frame += 0.25 |
|
||||
tmp_opath = os.path.join(tmp_dir, "output.gif") |
|
||||
with imageio.get_writer(tmp_opath, fps=5, mode='I') as writer: |
|
||||
for filename in files: |
|
||||
image = imageio.imread(filename) |
|
||||
writer.append_data(image) |
|
||||
elif clip.duration > int(frame): |
|
||||
clip.save_frame(tmp_opath, t=int(frame)) |
|
||||
else: |
|
||||
clip.save_frame(tmp_opath, t=int(0)) |
|
||||
if os.path.isfile(tmp_opath): |
|
||||
with open(tmp_opath, 'rb') as file: |
|
||||
if export == 'file': |
|
||||
return io.BytesIO(file.read()) |
|
||||
elif export == 'base64': |
|
||||
return base64.b64encode(file.read()) |
|
||||
else: |
|
||||
return file.read() |
|
||||
else: |
|
||||
raise ValueError("No output could be created from the video.") |
|
||||
finally: |
|
||||
try: |
|
||||
clip.reader.close() |
|
||||
del clip.reader |
|
||||
if clip.audio != None: |
|
||||
clip.audio.reader.close_proc() |
|
||||
del clip.audio |
|
||||
del clip |
|
||||
except Exception as e: |
|
||||
sys.exc_clear() |
|
||||
finally: |
|
||||
try: |
|
||||
shutil.rmtree(tmp_dir) |
|
||||
except PermissionError: |
|
||||
_logger.warn("Temporary directory could not be deleted.") |
|
||||
else: |
|
||||
raise ValueError("No output could be generated.") |
|
||||
|
################################################################################### |
||||
|
# |
||||
|
# Copyright (C) 2018 MuK IT GmbH |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################### |
||||
|
|
||||
|
import os |
||||
|
import io |
||||
|
import sys |
||||
|
import PyPDF2 |
||||
|
import base64 |
||||
|
import shutil |
||||
|
import urllib |
||||
|
import logging |
||||
|
import tempfile |
||||
|
import mimetypes |
||||
|
|
||||
|
from contextlib import closing |
||||
|
|
||||
|
from odoo.tools import config |
||||
|
from odoo.tools.mimetypes import guess_mimetype |
||||
|
|
||||
|
from odoo.addons.muk_utils.tools import utils_os |
||||
|
from odoo.addons.muk_converter.service import unoconv |
||||
|
|
||||
|
_logger = logging.getLogger(__name__) |
||||
|
|
||||
|
try: |
||||
|
from wand.image import Image |
||||
|
from wand.color import Color |
||||
|
except ImportError: |
||||
|
Image = False |
||||
|
Color = False |
||||
|
_logger.warn('Cannot `import wand`.') |
||||
|
|
||||
|
try: |
||||
|
import imageio |
||||
|
except ImportError: |
||||
|
imageio = False |
||||
|
_logger.warn('Cannot `import imageio`.') |
||||
|
|
||||
|
try: |
||||
|
from moviepy.editor import VideoFileClip |
||||
|
except ImportError: |
||||
|
VideoFileClip = False |
||||
|
_logger.warn('Cannot `import moviepy`.') |
||||
|
|
||||
|
FORMATS = [ |
||||
|
"png", "jpg", "jepg" |
||||
|
] |
||||
|
|
||||
|
VIDEO_IMPORTS = [ |
||||
|
"mp4", "mov", "wav", "avi", "mpg", "flv", "wmv", "webm" |
||||
|
] |
||||
|
|
||||
|
PDF_IMPORTS = [ |
||||
|
"pdf" |
||||
|
] |
||||
|
|
||||
|
WAND_IMPORTS = [ |
||||
|
"aai", "art", "arw", "avi", "avs", "bpg", "brf", "cals", "cgm", "cin", "cip", "cmyk", "cmyka", "svg", |
||||
|
"cr2", "crw", "cur", "cut", "dcm", "dcr", "dcx", "dds", "dib", "djvu", "dng", "dot", "dpx", "tim", |
||||
|
"emf", "epdf", "epi", "eps", "eps2", "eps3", "epsf", "epsi", "ept", "exr", "fax", "fig", "fits", |
||||
|
"fpx", "gplt", "gray", "graya", "hdr", "hdr", "heic", "hpgl", "hrz", "html", "ico", "info", "ttf", |
||||
|
"inline", "isobrl", "isobrl6", "jbig", "jng", "jp2", "jpt", "j2c", "j2k", "jxr", "json", "man", "bmp", |
||||
|
"mat", "miff", "mono", "mng", "m2v", "mpeg", "mpc", "mpr", "mrw", "msl", "mtv", "mvg", "nef", "yuv", |
||||
|
"orf", "otb", "p7", "palm", "pam", "clipboard", "pbm", "pcd", "pcds", "pcl", "pcx", "pdb", "jpe", |
||||
|
"pef", "pes", "pfa", "pfb", "pfm", "pgm", "picon", "pict", "pix", "png8", "png00", "png24", "tiff", |
||||
|
"png32", "png48", "png64", "pnm", "ppm", "ps", "ps2", "ps3", "psb", "psd", "ptif", "pwp", "rad", |
||||
|
"raf", "rgb", "rgba", "rgf", "rla", "rle", "sct", "sfw", "sgi", "shtml", "sid", " mrsid", "jpeg", |
||||
|
"sparse-color", "sun", "tga", "ubrl", "ubrl6", "uyvy", "vicar", "viff", "wbmp", "jpg", "png", "uil", |
||||
|
"wdp", "webp", "wmf", "wpg", "x", "xbm", "xcf", "xpm", "xwd", "x3f", "ycbcr", "ycbcra", "bmp3", "bmp2", |
||||
|
] |
||||
|
|
||||
|
def formats(): |
||||
|
return FORMATS |
||||
|
|
||||
|
def imports(): |
||||
|
return VIDEO_IMPORTS + PDF_IMPORTS + WAND_IMPORTS + unoconv.UNOCONV_IMPORTS |
||||
|
|
||||
|
def create_thumbnail(binary, mimetype=None, filename=None, export="binary", format="png", page=0, frame=0, |
||||
|
animation=False, video_resize={'width': 256}, image_resize='256x256>', image_crop=None): |
||||
|
""" |
||||
|
Converts a thumbnail for a given file. |
||||
|
|
||||
|
:param binary: The binary value. |
||||
|
:param mimetype: The mimetype of the binary value. |
||||
|
:param filename: The filename of the binary value. |
||||
|
:param export: The output format (binary, file, base64). |
||||
|
:param format: Specify the output format for the document. |
||||
|
:param page: Specifies the page if the file has several pages, e.g. if it is a PDF file. |
||||
|
:param frame: Specifies the frame if the file has several frames, e.g. if it is a video file. |
||||
|
:param animation: In this case, the parameter frame specifies the number of frames. |
||||
|
:param video_resize: Specify to resize the output image. |
||||
|
:param image_resize: Specify to resize the output image. |
||||
|
:param image_crop: Specify to crop the output image. |
||||
|
:return: Returns the output depending on the given format. |
||||
|
:raises ValueError: The file extension could not be determined or the format is invalid. |
||||
|
""" |
||||
|
extension = utils_os.get_extension(binary, filename, mimetype) |
||||
|
if not extension: |
||||
|
raise ValueError("The file extension could not be determined.") |
||||
|
if format not in FORMATS: |
||||
|
raise ValueError("Invalid export format.") |
||||
|
if extension not in (VIDEO_IMPORTS + PDF_IMPORTS + WAND_IMPORTS + unoconv.UNOCONV_IMPORTS): |
||||
|
raise ValueError("Invalid import format.") |
||||
|
if not imageio or not Image or not VideoFileClip: |
||||
|
raise ValueError("Some libraries couldn't be imported.") |
||||
|
image_data = None |
||||
|
image_extension = extension |
||||
|
if extension in WAND_IMPORTS: |
||||
|
image_data = binary |
||||
|
elif not image_data and (extension in PDF_IMPORTS or extension in unoconv.UNOCONV_IMPORTS): |
||||
|
pdf_data = binary if extension in PDF_IMPORTS else None |
||||
|
if not pdf_data: |
||||
|
image_extension = "pdf" |
||||
|
pdf_data = unoconv.unoconv.convert(binary, mimetype, filename) |
||||
|
reader = PyPDF2.PdfFileReader(io.BytesIO(pdf_data)) |
||||
|
writer = PyPDF2.PdfFileWriter() |
||||
|
if reader.getNumPages() >= page: |
||||
|
writer.addPage(reader.getPage(page)) |
||||
|
else: |
||||
|
writer.addPage(reader.getPage(0)) |
||||
|
pdf_bytes = io.BytesIO() |
||||
|
writer.write(pdf_bytes) |
||||
|
image_data = pdf_bytes.getvalue() |
||||
|
if image_data: |
||||
|
with Image(blob=image_data, format=image_extension) as thumbnail: |
||||
|
thumbnail.format = format |
||||
|
if image_extension == "pdf": |
||||
|
thumbnail.background_color = Color('white') |
||||
|
thumbnail.alpha_channel = 'remove' |
||||
|
if image_resize: |
||||
|
thumbnail.transform(resize=image_resize) |
||||
|
if image_crop: |
||||
|
thumbnail.transform(crop=image_crop) |
||||
|
if export == 'file': |
||||
|
return io.BytesIO(thumbnail.make_blob()) |
||||
|
elif export == 'base64': |
||||
|
return base64.b64encode(thumbnail.make_blob()) |
||||
|
else: |
||||
|
return thumbnail.make_blob() |
||||
|
elif extension in VIDEO_IMPORTS: |
||||
|
tmp_dir = tempfile.mkdtemp() |
||||
|
try: |
||||
|
tmp_wpath = os.path.join(tmp_dir, "tmpfile.%s" % extension) |
||||
|
if os.name == 'nt': |
||||
|
tmp_wpath = tmp_wpath.replace("\\", "/") |
||||
|
with closing(open(tmp_wpath, 'wb')) as file: |
||||
|
file.write(binary) |
||||
|
clip = VideoFileClip(tmp_wpath) |
||||
|
try: |
||||
|
tmp_opath = os.path.join(tmp_dir, "output.%s" % format) |
||||
|
clip.resize(**video_resize) |
||||
|
if animation: |
||||
|
files = [] |
||||
|
current_frame = 0 |
||||
|
while clip.duration > current_frame and current_frame < frame: |
||||
|
filename = os.path.join(tmp_dir, "output_%s.png" % frame) |
||||
|
clip.save_frame(filename, t=frame) |
||||
|
files.append(filename) |
||||
|
frame += 0.25 |
||||
|
tmp_opath = os.path.join(tmp_dir, "output.gif") |
||||
|
with imageio.get_writer(tmp_opath, fps=5, mode='I') as writer: |
||||
|
for filename in files: |
||||
|
image = imageio.imread(filename) |
||||
|
writer.append_data(image) |
||||
|
elif clip.duration > int(frame): |
||||
|
clip.save_frame(tmp_opath, t=int(frame)) |
||||
|
else: |
||||
|
clip.save_frame(tmp_opath, t=int(0)) |
||||
|
if os.path.isfile(tmp_opath): |
||||
|
with open(tmp_opath, 'rb') as file: |
||||
|
if export == 'file': |
||||
|
return io.BytesIO(file.read()) |
||||
|
elif export == 'base64': |
||||
|
return base64.b64encode(file.read()) |
||||
|
else: |
||||
|
return file.read() |
||||
|
else: |
||||
|
raise ValueError("No output could be created from the video.") |
||||
|
finally: |
||||
|
try: |
||||
|
clip.reader.close() |
||||
|
del clip.reader |
||||
|
if clip.audio != None: |
||||
|
clip.audio.reader.close_proc() |
||||
|
del clip.audio |
||||
|
del clip |
||||
|
except Exception as e: |
||||
|
sys.exc_clear() |
||||
|
finally: |
||||
|
try: |
||||
|
shutil.rmtree(tmp_dir) |
||||
|
except PermissionError: |
||||
|
_logger.warn("Temporary directory could not be deleted.") |
||||
|
else: |
||||
|
raise ValueError("No output could be generated.") |
Write
Preview
Loading…
Cancel
Save
Reference in new issue