Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f44aaf1

Browse files
committed
Inkscape shell mode.
1 parent 8a77cfb commit f44aaf1

File tree

1 file changed

+61
-6
lines changed

1 file changed

+61
-6
lines changed

lib/matplotlib/testing/compare.py

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@
77

88
import six
99

10+
import atexit
11+
import functools
1012
import hashlib
13+
import itertools
1114
import os
1215
import shutil
16+
import sys
1317

1418
import numpy as np
1519

@@ -128,6 +132,60 @@ def convert(old, new):
128132
return convert
129133

130134

135+
class _SVGConverter(object):
136+
def __init__(self):
137+
self._proc = None
138+
# We cannot rely on the GC to trigger `__del__` at exit because
139+
# other modules (e.g. `subprocess`) may already have their globals
140+
# set to `None`, which make `proc.communicate` or `proc.terminate`
141+
# fail. By relying on `atexit` we ensure the destructor runs before
142+
# `None`-setting occurs.
143+
atexit.register(self.__del__)
144+
145+
def _read_to_terminator(self):
146+
stream = iter(functools.partial(self._proc.stdout.read, 1), b"")
147+
terminator = (b"\n", b">")
148+
n = len(terminator)
149+
its = itertools.tee(stream, n)
150+
for i, it in enumerate(its):
151+
next(itertools.islice(it, i, i), None) # Advance `it` by `i`.
152+
while True:
153+
window = tuple(map(next, its))
154+
if len(window) == n:
155+
if window == terminator:
156+
break
157+
else:
158+
continue
159+
else:
160+
# One of the `next(it)` raised StopIteration, so the tuple is
161+
# shorter.
162+
break
163+
164+
def __call__(self, orig, dest):
165+
if not self._proc:
166+
self._proc = subprocess.Popen([str("inkscape"), "--shell"],
167+
stdin=subprocess.PIPE,
168+
stdout=subprocess.PIPE)
169+
self._read_to_terminator()
170+
try:
171+
fsencode = os.fsencode
172+
except AttributeError: # Py2.
173+
def fsencode(s):
174+
return s.encode(sys.getfilesystemencoding())
175+
self._proc.stdin.write(
176+
fsencode("{} --export-png={}\n".format(orig, dest)))
177+
self._proc.stdin.flush()
178+
self._read_to_terminator()
179+
180+
def __del__(self):
181+
if self._proc:
182+
if self._proc.poll() is None: # Not exited yet.
183+
self._proc.communicate(b"quit\n")
184+
self._proc.wait()
185+
self._proc.stdin.close()
186+
self._proc.stdout.close()
187+
188+
131189
def _update_converter():
132190
gs, gs_v = matplotlib.checkdep_ghostscript()
133191
if gs_v is not None:
@@ -138,9 +196,7 @@ def cmd(old, new):
138196
converter['eps'] = make_external_conversion_command(cmd)
139197

140198
if matplotlib.checkdep_inkscape() is not None:
141-
def cmd(old, new):
142-
return [str('inkscape'), '-z', old, '--export-png', new]
143-
converter['svg'] = make_external_conversion_command(cmd)
199+
converter['svg'] = _SVGConverter()
144200

145201

146202
#: A dictionary that maps filename extensions to functions which
@@ -363,9 +419,8 @@ def save_diff_image(expected, actual, output):
363419
actual, actualImage, expected, expectedImage)
364420
expectedImage = np.array(expectedImage).astype(float)
365421
actualImage = np.array(actualImage).astype(float)
366-
assert expectedImage.ndim == actualImage.ndim
367-
assert expectedImage.shape == actualImage.shape
368-
absDiffImage = abs(expectedImage - actualImage)
422+
assert expectedImage.shape[:2] == actualImage.shape[:2]
423+
absDiffImage = np.abs(expectedImage[:, :, :3] - actualImage[:, :, :3])
369424

370425
# expand differences in luminance domain
371426
absDiffImage *= 255 * 10

0 commit comments

Comments
 (0)