cmlibs.exporter 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cmlibs.exporter-0.4.0/LICENSE +14 -0
- cmlibs.exporter-0.4.0/PKG-INFO +61 -0
- cmlibs.exporter-0.4.0/README.rst +28 -0
- cmlibs.exporter-0.4.0/setup.cfg +4 -0
- cmlibs.exporter-0.4.0/setup.py +58 -0
- cmlibs.exporter-0.4.0/src/cmlibs/__init__.py +3 -0
- cmlibs.exporter-0.4.0/src/cmlibs/exporter/__init__.py +1 -0
- cmlibs.exporter-0.4.0/src/cmlibs/exporter/base.py +87 -0
- cmlibs.exporter-0.4.0/src/cmlibs/exporter/baseimage.py +157 -0
- cmlibs.exporter-0.4.0/src/cmlibs/exporter/errors.py +11 -0
- cmlibs.exporter-0.4.0/src/cmlibs/exporter/image.py +20 -0
- cmlibs.exporter-0.4.0/src/cmlibs/exporter/thumbnail.py +23 -0
- cmlibs.exporter-0.4.0/src/cmlibs/exporter/webgl.py +177 -0
- cmlibs.exporter-0.4.0/src/cmlibs.exporter.egg-info/PKG-INFO +61 -0
- cmlibs.exporter-0.4.0/src/cmlibs.exporter.egg-info/SOURCES.txt +17 -0
- cmlibs.exporter-0.4.0/src/cmlibs.exporter.egg-info/dependency_links.txt +1 -0
- cmlibs.exporter-0.4.0/src/cmlibs.exporter.egg-info/not-zip-safe +1 -0
- cmlibs.exporter-0.4.0/src/cmlibs.exporter.egg-info/requires.txt +8 -0
- cmlibs.exporter-0.4.0/src/cmlibs.exporter.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
Copyright 2021 University of Auckland
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: cmlibs.exporter
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: CMLibs Export functions.
|
|
5
|
+
Home-page: https://github.com/CMLibs-Bindings/cmlibs.exporter
|
|
6
|
+
Author: Hugh Sorby
|
|
7
|
+
Author-email: h.sorby@auckland.ac.nz
|
|
8
|
+
License: Apache Software License
|
|
9
|
+
Description:
|
|
10
|
+
===============
|
|
11
|
+
CMLibs Exporter
|
|
12
|
+
===============
|
|
13
|
+
|
|
14
|
+
CMLibs exporter classes. This software can be found on PyPi and installed with the following command::
|
|
15
|
+
|
|
16
|
+
pip install cmlibs.exporter
|
|
17
|
+
|
|
18
|
+
When using the thumbnail exporter there are additional requirements for hardware or software rendering.
|
|
19
|
+
To install the thumbnail exporter with support for hardware rendering install *cmlibs.exporter* with::
|
|
20
|
+
|
|
21
|
+
pip install 'cmlibs.exporter[thumbnail_hardware]'
|
|
22
|
+
|
|
23
|
+
To install the thumbnail exporter with support for software rendering install *cmlibs.exporter* with::
|
|
24
|
+
|
|
25
|
+
pip install 'cmlibs.exporter[thumbnail_software]'
|
|
26
|
+
|
|
27
|
+
To force the use of the software renderer even when hardware rendering is available, set an environment variable like so::
|
|
28
|
+
|
|
29
|
+
OC_EXPORTER_RENDERER=osmesa
|
|
30
|
+
|
|
31
|
+
either in the environment the exporter is run in or before calling the export thumbnail method.
|
|
32
|
+
|
|
33
|
+
Distribution
|
|
34
|
+
============
|
|
35
|
+
|
|
36
|
+
This software uses regex to extract the version number information from the package. The version number for this package is stored in 'src/cmlibs/exporter/__init__.py'
|
|
37
|
+
|
|
38
|
+
License
|
|
39
|
+
=======
|
|
40
|
+
|
|
41
|
+
::
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
Copyright 2021 University of Auckland
|
|
45
|
+
|
|
46
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
47
|
+
you may not use this file except in compliance with the License.
|
|
48
|
+
You may obtain a copy of the License at
|
|
49
|
+
|
|
50
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
51
|
+
|
|
52
|
+
Unless required by applicable law or agreed to in writing, software
|
|
53
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
54
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
55
|
+
See the License for the specific language governing permissions and
|
|
56
|
+
limitations under the License.
|
|
57
|
+
|
|
58
|
+
Platform: UNKNOWN
|
|
59
|
+
Description-Content-Type: text/x-rst
|
|
60
|
+
Provides-Extra: thumbnail_hardware
|
|
61
|
+
Provides-Extra: thumbnail_software
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
===============
|
|
3
|
+
CMLibs Exporter
|
|
4
|
+
===============
|
|
5
|
+
|
|
6
|
+
CMLibs exporter classes. This software can be found on PyPi and installed with the following command::
|
|
7
|
+
|
|
8
|
+
pip install cmlibs.exporter
|
|
9
|
+
|
|
10
|
+
When using the thumbnail exporter there are additional requirements for hardware or software rendering.
|
|
11
|
+
To install the thumbnail exporter with support for hardware rendering install *cmlibs.exporter* with::
|
|
12
|
+
|
|
13
|
+
pip install 'cmlibs.exporter[thumbnail_hardware]'
|
|
14
|
+
|
|
15
|
+
To install the thumbnail exporter with support for software rendering install *cmlibs.exporter* with::
|
|
16
|
+
|
|
17
|
+
pip install 'cmlibs.exporter[thumbnail_software]'
|
|
18
|
+
|
|
19
|
+
To force the use of the software renderer even when hardware rendering is available, set an environment variable like so::
|
|
20
|
+
|
|
21
|
+
OC_EXPORTER_RENDERER=osmesa
|
|
22
|
+
|
|
23
|
+
either in the environment the exporter is run in or before calling the export thumbnail method.
|
|
24
|
+
|
|
25
|
+
Distribution
|
|
26
|
+
============
|
|
27
|
+
|
|
28
|
+
This software uses regex to extract the version number information from the package. The version number for this package is stored in 'src/cmlibs/exporter/__init__.py'
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import io
|
|
2
|
+
import os
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
from setuptools import setup, find_packages
|
|
6
|
+
|
|
7
|
+
here = os.path.abspath(os.path.dirname(__file__))
|
|
8
|
+
|
|
9
|
+
with open(os.path.join(here, 'src', 'cmlibs', 'exporter', '__init__.py')) as fd:
|
|
10
|
+
version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]',
|
|
11
|
+
fd.read(), re.MULTILINE).group(1)
|
|
12
|
+
|
|
13
|
+
if not version:
|
|
14
|
+
raise RuntimeError('Cannot find version information')
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def readfile(filename, split=False):
|
|
18
|
+
with io.open(filename, encoding="utf-8") as stream:
|
|
19
|
+
if split:
|
|
20
|
+
return stream.read().split("\n")
|
|
21
|
+
return stream.read()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
readme = readfile("README.rst", split=True)
|
|
25
|
+
readme.append('License')
|
|
26
|
+
readme.append('=======')
|
|
27
|
+
readme.append('')
|
|
28
|
+
readme.append('::')
|
|
29
|
+
readme.append('')
|
|
30
|
+
readme.append('')
|
|
31
|
+
|
|
32
|
+
software_licence = readfile("LICENSE")
|
|
33
|
+
|
|
34
|
+
requires = ['cmlibs.argon >= 0.4.0', 'cmlibs.zinc']
|
|
35
|
+
|
|
36
|
+
setup(
|
|
37
|
+
name='cmlibs.exporter',
|
|
38
|
+
version=version,
|
|
39
|
+
description='CMLibs Export functions.',
|
|
40
|
+
long_description='\n'.join(readme) + software_licence,
|
|
41
|
+
long_description_content_type='text/x-rst',
|
|
42
|
+
classifiers=[],
|
|
43
|
+
author='Hugh Sorby',
|
|
44
|
+
author_email='h.sorby@auckland.ac.nz',
|
|
45
|
+
url='https://github.com/CMLibs-Bindings/cmlibs.exporter',
|
|
46
|
+
license='Apache Software License',
|
|
47
|
+
license_files=("LICENSE",),
|
|
48
|
+
packages=find_packages("src"),
|
|
49
|
+
package_dir={"": "src"},
|
|
50
|
+
include_package_data=True,
|
|
51
|
+
zip_safe=False,
|
|
52
|
+
install_requires=requires,
|
|
53
|
+
extras_require={
|
|
54
|
+
"thumbnail_hardware": ["PySide6"],
|
|
55
|
+
"thumbnail_software": ["PyOpenGL"],
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.4.0"
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from cmlibs.argon.argondocument import ArgonDocument
|
|
4
|
+
from cmlibs.argon.argonerror import ArgonError
|
|
5
|
+
from cmlibs.argon.argonlogger import ArgonLogger
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BaseExporter(object):
|
|
9
|
+
|
|
10
|
+
def __init__(self, output_prefix):
|
|
11
|
+
self._prefix = output_prefix
|
|
12
|
+
self._document = None
|
|
13
|
+
self._filename = None
|
|
14
|
+
self._initialTime = None
|
|
15
|
+
self._finishTime = None
|
|
16
|
+
self._numberOfTimeSteps = 10
|
|
17
|
+
|
|
18
|
+
def set_document(self, document):
|
|
19
|
+
"""
|
|
20
|
+
Set the document to export.
|
|
21
|
+
|
|
22
|
+
:param document: Set the document to export.
|
|
23
|
+
"""
|
|
24
|
+
self._document = document
|
|
25
|
+
|
|
26
|
+
def set_filename(self, filename):
|
|
27
|
+
"""
|
|
28
|
+
Set filename.
|
|
29
|
+
|
|
30
|
+
:param filename: The filename for the Argon document.
|
|
31
|
+
"""
|
|
32
|
+
self._filename = filename
|
|
33
|
+
|
|
34
|
+
def set_parameters(self, parameters):
|
|
35
|
+
"""
|
|
36
|
+
Set the parameters for this exporter.
|
|
37
|
+
The parameters must have values for:
|
|
38
|
+
|
|
39
|
+
* numberOfTimeSteps
|
|
40
|
+
* initialTime
|
|
41
|
+
* finishTime
|
|
42
|
+
* prefix
|
|
43
|
+
|
|
44
|
+
:param parameters: A *dict* of parameters.
|
|
45
|
+
"""
|
|
46
|
+
self._numberOfTimeSteps = parameters["numberOfTimeSteps"]
|
|
47
|
+
self._initialTime = parameters["initialTime"]
|
|
48
|
+
self._finishTime = parameters["finishTime"]
|
|
49
|
+
self._prefix = parameters["prefix"]
|
|
50
|
+
|
|
51
|
+
def export(self):
|
|
52
|
+
raise NotImplementedError("export() not implemented")
|
|
53
|
+
|
|
54
|
+
def load(self, filename):
|
|
55
|
+
"""
|
|
56
|
+
Loads the named Argon file and on success sets filename as the current location.
|
|
57
|
+
Emits documentChange separately if new document loaded, including if existing document cleared due to load failure.
|
|
58
|
+
|
|
59
|
+
:return: True on success, otherwise False.
|
|
60
|
+
"""
|
|
61
|
+
if filename is None:
|
|
62
|
+
return False
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
with open(filename, 'r') as f:
|
|
66
|
+
state = f.read()
|
|
67
|
+
|
|
68
|
+
current_wd = os.getcwd()
|
|
69
|
+
# set current directory to path from file, to support scripts and FieldML with external resources
|
|
70
|
+
if not os.path.isabs(filename):
|
|
71
|
+
filename = os.path.abspath(filename)
|
|
72
|
+
path = os.path.dirname(filename)
|
|
73
|
+
os.chdir(path)
|
|
74
|
+
self._document = ArgonDocument()
|
|
75
|
+
self._document.initialiseVisualisationContents()
|
|
76
|
+
self._document.deserialize(state)
|
|
77
|
+
os.chdir(current_wd)
|
|
78
|
+
return True
|
|
79
|
+
except (ArgonError, IOError, ValueError) as e:
|
|
80
|
+
ArgonLogger.getLogger().error("Failed to load Argon visualisation " + filename + ": " + str(e))
|
|
81
|
+
except Exception as e:
|
|
82
|
+
ArgonLogger.getLogger().error("Failed to load Argon visualisation " + filename + ": Unknown error " + str(e))
|
|
83
|
+
|
|
84
|
+
return False
|
|
85
|
+
|
|
86
|
+
def _form_full_filename(self, filename):
|
|
87
|
+
return filename if self._output_target is None else os.path.join(self._output_target, filename)
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base class for exporting an Argon document to a JPEG image.
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
from cmlibs.argon.argondocument import ArgonDocument
|
|
8
|
+
from cmlibs.exporter.base import BaseExporter
|
|
9
|
+
from cmlibs.exporter.errors import ExportImageError
|
|
10
|
+
from cmlibs.zinc.sceneviewer import Sceneviewer
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BaseImageExporter(BaseExporter):
|
|
14
|
+
"""
|
|
15
|
+
A base class for exporting visualisation described by an Argon document to JPEG.
|
|
16
|
+
By default the export will be use PySide6 to render the scene.
|
|
17
|
+
An alternative is to use OSMesa for software rendering.
|
|
18
|
+
To use OSMesa as the renderer either set the environment variable
|
|
19
|
+
OC_EXPORTER_RENDERER to 'osmesa' or not have PySide6 available in the
|
|
20
|
+
calling environment.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, width, height, name_postfix, output_target=None, output_prefix=None):
|
|
24
|
+
"""
|
|
25
|
+
:param output_target: The target directory to export the visualisation to.
|
|
26
|
+
:param output_prefix: The prefix to apply to the output.
|
|
27
|
+
"""
|
|
28
|
+
super(BaseImageExporter, self).__init__(output_prefix)
|
|
29
|
+
self._output_target = '.' if output_target is None else output_target
|
|
30
|
+
self._width = width
|
|
31
|
+
self._height = height
|
|
32
|
+
self._name_postfix = name_postfix
|
|
33
|
+
|
|
34
|
+
def _form_full_filename(self, filename):
|
|
35
|
+
return filename if self._output_target is None else os.path.join(self._output_target, filename)
|
|
36
|
+
|
|
37
|
+
def export(self, output_target=None):
|
|
38
|
+
"""
|
|
39
|
+
Export the current document to *output_target*. If no *output_target* is given then
|
|
40
|
+
the *output_target* set at initialisation is used.
|
|
41
|
+
|
|
42
|
+
If there is no current document then one will be loaded from the current filename.
|
|
43
|
+
|
|
44
|
+
:param output_target: Output directory location.
|
|
45
|
+
"""
|
|
46
|
+
if output_target is not None:
|
|
47
|
+
self._output_target = output_target
|
|
48
|
+
|
|
49
|
+
if self._document is None:
|
|
50
|
+
self._document = ArgonDocument()
|
|
51
|
+
self._document.initialiseVisualisationContents()
|
|
52
|
+
self.load(self._filename)
|
|
53
|
+
else:
|
|
54
|
+
state = self._document.serialize()
|
|
55
|
+
self._document.freeVisualisationContents()
|
|
56
|
+
self._document.initialiseVisualisationContents()
|
|
57
|
+
self._document.deserialize(state)
|
|
58
|
+
|
|
59
|
+
self._document.checkVersion("0.3.0")
|
|
60
|
+
|
|
61
|
+
self.export_image()
|
|
62
|
+
|
|
63
|
+
def export_image(self):
|
|
64
|
+
"""
|
|
65
|
+
Export graphics into an image format.
|
|
66
|
+
"""
|
|
67
|
+
pyside6_opengl_failed = True
|
|
68
|
+
if "OC_EXPORTER_RENDERER" not in os.environ or os.environ["OC_EXPORTER_RENDERER"] != "osmesa":
|
|
69
|
+
try:
|
|
70
|
+
from PySide6 import QtGui
|
|
71
|
+
|
|
72
|
+
if QtGui.QGuiApplication.instance() is None:
|
|
73
|
+
QtGui.QGuiApplication([])
|
|
74
|
+
|
|
75
|
+
off_screen = QtGui.QOffscreenSurface()
|
|
76
|
+
off_screen.create()
|
|
77
|
+
if off_screen.isValid():
|
|
78
|
+
context = QtGui.QOpenGLContext()
|
|
79
|
+
if context.create():
|
|
80
|
+
context.makeCurrent(off_screen)
|
|
81
|
+
pyside6_opengl_failed = False
|
|
82
|
+
|
|
83
|
+
except ImportError:
|
|
84
|
+
pyside6_opengl_failed = True
|
|
85
|
+
|
|
86
|
+
mesa_context = None
|
|
87
|
+
mesa_opengl_failed = True
|
|
88
|
+
if pyside6_opengl_failed:
|
|
89
|
+
try:
|
|
90
|
+
from OpenGL import GL
|
|
91
|
+
from OpenGL import arrays
|
|
92
|
+
from OpenGL.osmesa import (
|
|
93
|
+
OSMesaCreateContextAttribs, OSMesaMakeCurrent, OSMESA_FORMAT,
|
|
94
|
+
OSMESA_RGBA, OSMESA_PROFILE, OSMESA_COMPAT_PROFILE,
|
|
95
|
+
OSMESA_CONTEXT_MAJOR_VERSION, OSMESA_CONTEXT_MINOR_VERSION,
|
|
96
|
+
OSMESA_DEPTH_BITS
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
attrs = arrays.GLintArray.asArray([
|
|
100
|
+
OSMESA_FORMAT, OSMESA_RGBA,
|
|
101
|
+
OSMESA_DEPTH_BITS, 24,
|
|
102
|
+
OSMESA_PROFILE, OSMESA_COMPAT_PROFILE,
|
|
103
|
+
OSMESA_CONTEXT_MAJOR_VERSION, 2,
|
|
104
|
+
OSMESA_CONTEXT_MINOR_VERSION, 1,
|
|
105
|
+
0
|
|
106
|
+
])
|
|
107
|
+
mesa_context = OSMesaCreateContextAttribs(attrs, None)
|
|
108
|
+
mesa_buffer = arrays.GLubyteArray.zeros((self._width, self._height, 4))
|
|
109
|
+
result = OSMesaMakeCurrent(mesa_context, mesa_buffer, GL.GL_UNSIGNED_BYTE, self._width, self._height)
|
|
110
|
+
if result:
|
|
111
|
+
mesa_opengl_failed = False
|
|
112
|
+
except ImportError:
|
|
113
|
+
mesa_opengl_failed = True
|
|
114
|
+
|
|
115
|
+
if pyside6_opengl_failed and mesa_opengl_failed:
|
|
116
|
+
raise ExportImageError('Image export not supported without optional requirements PySide6 for hardware rendering or OSMesa for software rendering.')
|
|
117
|
+
|
|
118
|
+
zinc_context = self._document.getZincContext()
|
|
119
|
+
view_manager = self._document.getViewManager()
|
|
120
|
+
|
|
121
|
+
root_region = zinc_context.getDefaultRegion()
|
|
122
|
+
sceneviewermodule = zinc_context.getSceneviewermodule()
|
|
123
|
+
|
|
124
|
+
views = view_manager.getViews()
|
|
125
|
+
|
|
126
|
+
for view in views:
|
|
127
|
+
name = view.getName()
|
|
128
|
+
scenes = view.getScenes()
|
|
129
|
+
if len(scenes) == 1:
|
|
130
|
+
scene_description = scenes[0]["Sceneviewer"].serialize()
|
|
131
|
+
|
|
132
|
+
sceneviewer = sceneviewermodule.createSceneviewer(Sceneviewer.BUFFERING_MODE_DOUBLE, Sceneviewer.STEREO_MODE_DEFAULT)
|
|
133
|
+
sceneviewer.setViewportSize(self._width, self._height)
|
|
134
|
+
|
|
135
|
+
if not (self._initialTime is None or self._finishTime is None):
|
|
136
|
+
raise NotImplementedError('Time varying image export is not implemented.')
|
|
137
|
+
|
|
138
|
+
sceneviewer.readDescription(json.dumps(scene_description))
|
|
139
|
+
# Workaround for order independent transparency producing a white output
|
|
140
|
+
# and in any case, sceneviewer transparency layers were not being serialised by Zinc.
|
|
141
|
+
if sceneviewer.getTransparencyMode() == Sceneviewer.TRANSPARENCY_MODE_ORDER_INDEPENDENT:
|
|
142
|
+
sceneviewer.setTransparencyMode(Sceneviewer.TRANSPARENCY_MODE_SLOW)
|
|
143
|
+
|
|
144
|
+
scene_path = scene_description["Scene"]
|
|
145
|
+
scene = root_region.getScene()
|
|
146
|
+
if scene_path is not None:
|
|
147
|
+
scene_region = root_region.findChildByName(scene_path)
|
|
148
|
+
if scene_region.isValid():
|
|
149
|
+
scene = scene_region.getScene()
|
|
150
|
+
|
|
151
|
+
sceneviewer.setScene(scene)
|
|
152
|
+
|
|
153
|
+
sceneviewer.writeImageToFile(os.path.join(self._output_target, f'{self._prefix}_{name}_{self._name_postfix}.jpeg'), False, self._width, self._height, 4, 0)
|
|
154
|
+
|
|
155
|
+
if mesa_context is not None:
|
|
156
|
+
from OpenGL.osmesa import OSMesaDestroyContext
|
|
157
|
+
OSMesaDestroyContext(mesa_context)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Export an Argon document to a JPEG file of size Width x Height.
|
|
3
|
+
"""
|
|
4
|
+
from cmlibs.exporter.baseimage import BaseImageExporter
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ArgonSceneExporter(BaseImageExporter):
|
|
8
|
+
"""
|
|
9
|
+
Export a visualisation described by an Argon document to JPEG image.
|
|
10
|
+
See the BaseImageExporter for rendering options.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, width, height, output_target=None, output_prefix=None):
|
|
14
|
+
"""
|
|
15
|
+
:param output_target: The target directory to export the visualisation to.
|
|
16
|
+
:param output_prefix: The prefix to apply to the output.
|
|
17
|
+
"""
|
|
18
|
+
local_output_target = '.' if output_target is None else output_target
|
|
19
|
+
local_output_prefix = "ArgonSceneExporterImage" if output_prefix is None else output_prefix
|
|
20
|
+
super(ArgonSceneExporter, self).__init__(width, height, "image", output_target=local_output_target, output_prefix=local_output_prefix)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Export an Argon document to a JPEG file of size 512x512.
|
|
3
|
+
"""
|
|
4
|
+
from cmlibs.exporter.baseimage import BaseImageExporter
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ArgonSceneExporter(BaseImageExporter):
|
|
8
|
+
"""
|
|
9
|
+
Export a visualisation described by an Argon document to JPEG thumbnail.
|
|
10
|
+
See the BaseImageExporter for rendering options.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, output_target=None, output_prefix=None):
|
|
14
|
+
"""
|
|
15
|
+
:param output_target: The target directory to export the visualisation to.
|
|
16
|
+
:param output_prefix: The prefix to apply to the output.
|
|
17
|
+
"""
|
|
18
|
+
local_output_target = '.' if output_target is None else output_target
|
|
19
|
+
local_output_prefix = "ArgonSceneExporterThumbnail" if output_prefix is None else output_prefix
|
|
20
|
+
super(ArgonSceneExporter, self).__init__(512, 512, "thumbnail", output_target=local_output_target, output_prefix=local_output_prefix)
|
|
21
|
+
|
|
22
|
+
def export_thumbnail(self):
|
|
23
|
+
self.export_image()
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Export an Argon document to WebGL documents suitable for scaffoldvuer.
|
|
3
|
+
"""
|
|
4
|
+
import math
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
from cmlibs.argon.argondocument import ArgonDocument
|
|
8
|
+
from cmlibs.exporter.base import BaseExporter
|
|
9
|
+
from cmlibs.exporter.errors import ExportWebGLError
|
|
10
|
+
|
|
11
|
+
from cmlibs.zinc.status import OK as ZINC_OK
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ArgonSceneExporter(BaseExporter):
|
|
15
|
+
"""
|
|
16
|
+
Export a visualisation described by an Argon document to webGL.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, output_target=None, output_prefix=None):
|
|
20
|
+
"""
|
|
21
|
+
:param output_target: The target directory to export the visualisation to.
|
|
22
|
+
:param output_prefix: The prefix for the exported file(s).
|
|
23
|
+
"""
|
|
24
|
+
super(ArgonSceneExporter, self).__init__("ArgonSceneExporterWebGL" if output_prefix is None else output_prefix)
|
|
25
|
+
self._output_target = output_target
|
|
26
|
+
|
|
27
|
+
def export(self, output_target=None):
|
|
28
|
+
"""
|
|
29
|
+
Export the current document to *output_target*. If no *output_target* is given then
|
|
30
|
+
the *output_target* set at initialisation is used.
|
|
31
|
+
|
|
32
|
+
If there is no current document then one will be loaded from the current filename.
|
|
33
|
+
|
|
34
|
+
:param output_target: Output directory location.
|
|
35
|
+
"""
|
|
36
|
+
if output_target is not None:
|
|
37
|
+
self._output_target = output_target
|
|
38
|
+
|
|
39
|
+
if self._document is None:
|
|
40
|
+
self._document = ArgonDocument()
|
|
41
|
+
self._document.initialiseVisualisationContents()
|
|
42
|
+
self.load(self._filename)
|
|
43
|
+
|
|
44
|
+
self._document.checkVersion("0.3.0")
|
|
45
|
+
|
|
46
|
+
self.export_view()
|
|
47
|
+
self.export_webgl()
|
|
48
|
+
|
|
49
|
+
def export_view(self):
|
|
50
|
+
"""Export sceneviewer parameters to JSON format"""
|
|
51
|
+
view_manager = self._document.getViewManager()
|
|
52
|
+
views = view_manager.getViews()
|
|
53
|
+
for view in views:
|
|
54
|
+
name = view.getName()
|
|
55
|
+
scenes = view.getScenes()
|
|
56
|
+
if len(scenes) == 1:
|
|
57
|
+
scene_description = scenes[0]["Sceneviewer"].serialize()
|
|
58
|
+
viewData = {'farPlane': scene_description['FarClippingPlane'], 'nearPlane': scene_description['NearClippingPlane'],
|
|
59
|
+
'eyePosition': scene_description['EyePosition'], 'targetPosition': scene_description['LookatPosition'],
|
|
60
|
+
'upVector': scene_description['UpVector'], 'viewAngle': scene_description['ViewAngle']}
|
|
61
|
+
|
|
62
|
+
view_file = self._form_full_filename(self._view_filename(name))
|
|
63
|
+
with open(view_file, 'w') as f:
|
|
64
|
+
json.dump(viewData, f)
|
|
65
|
+
|
|
66
|
+
def _view_filename(self, name):
|
|
67
|
+
return f"{self._prefix}_{name}_view.json"
|
|
68
|
+
|
|
69
|
+
def _define_default_view_obj(self):
|
|
70
|
+
view_obj = {}
|
|
71
|
+
view_manager = self._document.getViewManager()
|
|
72
|
+
view_name = view_manager.getActiveView()
|
|
73
|
+
if view_name is not None:
|
|
74
|
+
view_obj = {
|
|
75
|
+
"Type": "View",
|
|
76
|
+
"URL": self._view_filename(view_name)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return view_obj
|
|
80
|
+
|
|
81
|
+
def _define_settings_obj(self):
|
|
82
|
+
settings_obj = None
|
|
83
|
+
|
|
84
|
+
if self._initialTime is not None and self._finishTime is not None:
|
|
85
|
+
# /P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$/;
|
|
86
|
+
time_diff = int(self._finishTime - self._initialTime)
|
|
87
|
+
duration = f"PT{time_diff}S"
|
|
88
|
+
settings_obj = {
|
|
89
|
+
"Type": "Settings",
|
|
90
|
+
"Duration": duration,
|
|
91
|
+
"OriginalDuration": duration,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return settings_obj
|
|
95
|
+
|
|
96
|
+
def export_webgl(self):
|
|
97
|
+
"""
|
|
98
|
+
Export graphics into JSON format, one json export represents one
|
|
99
|
+
surface graphics.
|
|
100
|
+
"""
|
|
101
|
+
scene = self._document.getRootRegion().getZincRegion().getScene()
|
|
102
|
+
sceneSR = scene.createStreaminformationScene()
|
|
103
|
+
sceneSR.setIOFormat(sceneSR.IO_FORMAT_THREEJS)
|
|
104
|
+
if not (self._initialTime is None or self._finishTime is None):
|
|
105
|
+
sceneSR.setNumberOfTimeSteps(self._numberOfTimeSteps)
|
|
106
|
+
sceneSR.setInitialTime(self._initialTime)
|
|
107
|
+
sceneSR.setFinishTime(self._finishTime)
|
|
108
|
+
""" We want the geometries and colours change overtime """
|
|
109
|
+
sceneSR.setOutputTimeDependentVertices(1)
|
|
110
|
+
sceneSR.setOutputTimeDependentColours(1)
|
|
111
|
+
|
|
112
|
+
number = sceneSR.getNumberOfResourcesRequired()
|
|
113
|
+
if number == 0:
|
|
114
|
+
return
|
|
115
|
+
|
|
116
|
+
resources = []
|
|
117
|
+
"""Write out each graphics into a json file which can be rendered with ZincJS"""
|
|
118
|
+
for i in range(number):
|
|
119
|
+
resources.append(sceneSR.createStreamresourceMemory())
|
|
120
|
+
|
|
121
|
+
scene.write(sceneSR)
|
|
122
|
+
|
|
123
|
+
number_of_digits = math.floor(math.log10(number)) + 1
|
|
124
|
+
|
|
125
|
+
def _resource_filename(prefix, i_):
|
|
126
|
+
return f'{prefix}_{str(i_).zfill(number_of_digits)}.json'
|
|
127
|
+
|
|
128
|
+
"""Write out each resource into their own file"""
|
|
129
|
+
resource_count = 0
|
|
130
|
+
for i in range(number):
|
|
131
|
+
result, buffer = resources[i].getBuffer()
|
|
132
|
+
if result != ZINC_OK:
|
|
133
|
+
print('some sort of error')
|
|
134
|
+
continue
|
|
135
|
+
|
|
136
|
+
if buffer is None:
|
|
137
|
+
# Maybe this is a bug in the resource counting.
|
|
138
|
+
continue
|
|
139
|
+
|
|
140
|
+
buffer = buffer.decode()
|
|
141
|
+
|
|
142
|
+
if i == 0:
|
|
143
|
+
for j in range(number - 1):
|
|
144
|
+
"""
|
|
145
|
+
IMPORTANT: the replace name here is relative to your html page, so adjust it
|
|
146
|
+
accordingly.
|
|
147
|
+
"""
|
|
148
|
+
replaceName = f'"{_resource_filename(self._prefix, j + 1)}"'
|
|
149
|
+
old_name = '"memory_resource_' + str(j + 2) + '"'
|
|
150
|
+
buffer = buffer.replace(old_name, replaceName, 1)
|
|
151
|
+
|
|
152
|
+
view_obj = self._define_default_view_obj()
|
|
153
|
+
|
|
154
|
+
settings_obj = self._define_settings_obj()
|
|
155
|
+
|
|
156
|
+
obj = json.loads(buffer)
|
|
157
|
+
if obj is None:
|
|
158
|
+
raise ExportWebGLError('There is nothing to export')
|
|
159
|
+
|
|
160
|
+
obj.append(view_obj)
|
|
161
|
+
if settings_obj is not None:
|
|
162
|
+
obj.append(settings_obj)
|
|
163
|
+
|
|
164
|
+
buffer = json.dumps(obj)
|
|
165
|
+
|
|
166
|
+
if i == 0:
|
|
167
|
+
current_file = self._form_full_filename(self._prefix + '_metadata.json')
|
|
168
|
+
else:
|
|
169
|
+
current_file = self._form_full_filename(_resource_filename(self._prefix, resource_count))
|
|
170
|
+
|
|
171
|
+
with open(current_file, 'w') as f:
|
|
172
|
+
f.write(buffer)
|
|
173
|
+
|
|
174
|
+
resource_count += 1
|
|
175
|
+
|
|
176
|
+
def metadata_file(self):
|
|
177
|
+
return self._form_full_filename(self._prefix + '_metadata.json')
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: cmlibs.exporter
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: CMLibs Export functions.
|
|
5
|
+
Home-page: https://github.com/CMLibs-Bindings/cmlibs.exporter
|
|
6
|
+
Author: Hugh Sorby
|
|
7
|
+
Author-email: h.sorby@auckland.ac.nz
|
|
8
|
+
License: Apache Software License
|
|
9
|
+
Description:
|
|
10
|
+
===============
|
|
11
|
+
CMLibs Exporter
|
|
12
|
+
===============
|
|
13
|
+
|
|
14
|
+
CMLibs exporter classes. This software can be found on PyPi and installed with the following command::
|
|
15
|
+
|
|
16
|
+
pip install cmlibs.exporter
|
|
17
|
+
|
|
18
|
+
When using the thumbnail exporter there are additional requirements for hardware or software rendering.
|
|
19
|
+
To install the thumbnail exporter with support for hardware rendering install *cmlibs.exporter* with::
|
|
20
|
+
|
|
21
|
+
pip install 'cmlibs.exporter[thumbnail_hardware]'
|
|
22
|
+
|
|
23
|
+
To install the thumbnail exporter with support for software rendering install *cmlibs.exporter* with::
|
|
24
|
+
|
|
25
|
+
pip install 'cmlibs.exporter[thumbnail_software]'
|
|
26
|
+
|
|
27
|
+
To force the use of the software renderer even when hardware rendering is available, set an environment variable like so::
|
|
28
|
+
|
|
29
|
+
OC_EXPORTER_RENDERER=osmesa
|
|
30
|
+
|
|
31
|
+
either in the environment the exporter is run in or before calling the export thumbnail method.
|
|
32
|
+
|
|
33
|
+
Distribution
|
|
34
|
+
============
|
|
35
|
+
|
|
36
|
+
This software uses regex to extract the version number information from the package. The version number for this package is stored in 'src/cmlibs/exporter/__init__.py'
|
|
37
|
+
|
|
38
|
+
License
|
|
39
|
+
=======
|
|
40
|
+
|
|
41
|
+
::
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
Copyright 2021 University of Auckland
|
|
45
|
+
|
|
46
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
47
|
+
you may not use this file except in compliance with the License.
|
|
48
|
+
You may obtain a copy of the License at
|
|
49
|
+
|
|
50
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
51
|
+
|
|
52
|
+
Unless required by applicable law or agreed to in writing, software
|
|
53
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
54
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
55
|
+
See the License for the specific language governing permissions and
|
|
56
|
+
limitations under the License.
|
|
57
|
+
|
|
58
|
+
Platform: UNKNOWN
|
|
59
|
+
Description-Content-Type: text/x-rst
|
|
60
|
+
Provides-Extra: thumbnail_hardware
|
|
61
|
+
Provides-Extra: thumbnail_software
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.rst
|
|
3
|
+
setup.py
|
|
4
|
+
src/cmlibs/__init__.py
|
|
5
|
+
src/cmlibs.exporter.egg-info/PKG-INFO
|
|
6
|
+
src/cmlibs.exporter.egg-info/SOURCES.txt
|
|
7
|
+
src/cmlibs.exporter.egg-info/dependency_links.txt
|
|
8
|
+
src/cmlibs.exporter.egg-info/not-zip-safe
|
|
9
|
+
src/cmlibs.exporter.egg-info/requires.txt
|
|
10
|
+
src/cmlibs.exporter.egg-info/top_level.txt
|
|
11
|
+
src/cmlibs/exporter/__init__.py
|
|
12
|
+
src/cmlibs/exporter/base.py
|
|
13
|
+
src/cmlibs/exporter/baseimage.py
|
|
14
|
+
src/cmlibs/exporter/errors.py
|
|
15
|
+
src/cmlibs/exporter/image.py
|
|
16
|
+
src/cmlibs/exporter/thumbnail.py
|
|
17
|
+
src/cmlibs/exporter/webgl.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cmlibs
|