Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/wand/api.py : 45%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1""":mod:`wand.api` --- Low-level interfaces
2~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4.. versionchanged:: 0.1.10
5 Changed to throw :exc:`~exceptions.ImportError` instead of
6 :exc:`~exceptions.AttributeError` when the shared library fails to load.
8"""
9import ctypes
10import ctypes.util
11import itertools
12import os
13import os.path
14import platform
15import sys
16import traceback
17# Forward import for backwords compatibility.
18from .cdefs.structures import (AffineMatrix, MagickPixelPacket, PixelInfo,
19 PointInfo)
20if platform.system() == "Windows":
21 try:
22 import winreg
23 except ImportError:
24 import _winreg as winreg
26__all__ = ('AffineMatrix', 'MagickPixelPacket', 'library', 'libc', 'libmagick',
27 'load_library', 'PixelInfo', 'PointInfo')
30def library_paths():
31 """Iterates for library paths to try loading. The result paths are not
32 guaranteed that they exist.
34 :returns: a pair of libwand and libmagick paths. they can be the same.
35 path can be ``None`` as well
36 :rtype: :class:`tuple`
38 """
39 libwand = None
40 libmagick = None
41 versions = '', '-7', '-7.Q8', '-7.Q16', '-6', '-Q16', '-Q8', '-6.Q16'
42 options = '', 'HDRI', 'HDRI-2'
43 system = platform.system()
44 magick_home = os.environ.get('MAGICK_HOME')
45 magick_suffix = os.environ.get('WAND_MAGICK_LIBRARY_SUFFIX')
47 if system == 'Windows':
48 # ImageMagick installers normally install coder and filter DLLs in
49 # subfolders, we need to add those folders to PATH, otherwise loading
50 # the DLL later will fail.
51 try:
52 with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,
53 r"SOFTWARE\ImageMagick\Current") as reg_key:
54 libPath = winreg.QueryValueEx(reg_key, "LibPath")
55 coderPath = winreg.QueryValueEx(reg_key, "CoderModulesPath")
56 filterPath = winreg.QueryValueEx(reg_key, "FilterModulesPath")
57 magick_home = libPath[0]
58 os.environ['PATH'] += str((';' + libPath[0] + ";" +
59 coderPath[0] + ";" + filterPath[0]))
60 except OSError:
61 # otherwise use MAGICK_HOME, and we assume the coder and
62 # filter DLLs are in the same directory
63 pass
65 def magick_path(path):
66 return os.path.join(magick_home, *path)
67 combinations = itertools.product(versions, options)
68 suffixes = list()
69 if magick_suffix:
70 suffixes = str(magick_suffix).split(';')
71 # We need to convert the ``combinations`` generator to a list so we can
72 # iterate over it twice.
73 suffixes.extend(list(version + option for version, option in combinations))
74 if magick_home:
75 # exhaustively search for libraries in magick_home before calling
76 # find_library.
77 for suffix in suffixes:
78 # On Windows, the API is split between two libs. On other
79 # platforms, it's all contained in one.
80 if system == 'Windows':
81 libwand = 'CORE_RL_wand_{0}.dll'.format(suffix),
82 libmagick = 'CORE_RL_magick_{0}.dll'.format(suffix),
83 yield magick_path(libwand), magick_path(libmagick)
84 libwand = 'CORE_RL_MagickWand_{0}.dll'.format(suffix),
85 libmagick = 'CORE_RL_MagickCore_{0}.dll'.format(suffix),
86 yield magick_path(libwand), magick_path(libmagick)
87 libwand = 'libMagickWand{0}.dll'.format(suffix),
88 libmagick = 'libMagickCore{0}.dll'.format(suffix),
89 yield magick_path(libwand), magick_path(libmagick)
90 elif system == 'Darwin':
91 libwand = 'lib', 'libMagickWand{0}.dylib'.format(suffix),
92 yield magick_path(libwand), magick_path(libwand)
93 else:
94 libwand = 'lib', 'libMagickWand{0}.so'.format(suffix),
95 libmagick = 'lib', 'libMagickCore{0}.so'.format(suffix),
96 yield magick_path(libwand), magick_path(libmagick)
97 libwand = 'lib', 'libMagickWand{0}.so.6'.format(suffix),
98 libmagick = 'lib', 'libMagickCore{0}.so.6'.format(suffix),
99 yield magick_path(libwand), magick_path(libmagick)
100 for suffix in suffixes:
101 if system == 'Windows':
102 libwand = ctypes.util.find_library('CORE_RL_wand_' + suffix)
103 libmagick = ctypes.util.find_library('CORE_RL_magick_' + suffix)
104 yield libwand, libmagick
105 libwand = ctypes.util.find_library('CORE_RL_MagickWand_' + suffix)
106 libmagick = ctypes.util.find_library(
107 'CORE_RL_MagickCore_' + suffix
108 )
109 yield libwand, libmagick
110 libwand = ctypes.util.find_library('libMagickWand' + suffix)
111 libmagick = ctypes.util.find_library('libMagickCore' + suffix)
112 yield libwand, libmagick
113 else:
114 libwand = ctypes.util.find_library('MagickWand' + suffix)
115 yield libwand, libwand
118def load_library():
119 """Loads the MagickWand library.
121 :returns: the MagickWand library and the ImageMagick library
122 :rtype: :class:`ctypes.CDLL`
124 """
125 tried_paths = []
126 for libwand_path, libmagick_path in library_paths():
127 if libwand_path is None or libmagick_path is None:
128 continue
129 try:
130 tried_paths.append(libwand_path)
131 libwand = ctypes.CDLL(str(libwand_path))
132 if libwand_path == libmagick_path:
133 libmagick = libwand
134 else:
135 tried_paths.append(libmagick_path)
136 libmagick = ctypes.CDLL(str(libmagick_path))
137 except (IOError, OSError):
138 continue
139 return libwand, libmagick
140 raise IOError('cannot find library; tried paths: ' + repr(tried_paths))
143try:
144 # Preserve the module itself even if it fails to import
145 sys.modules['wand._api'] = sys.modules['wand.api']
146except KeyError:
147 # Loading the module locally or a non-standard setting
148 pass
150try:
151 libraries = load_library()
152except (OSError, IOError):
153 msg = 'http://docs.wand-py.org/en/latest/guide/install.html'
154 if sys.platform.startswith(('dragonfly', 'freebsd')):
155 msg = 'pkg install'
156 elif sys.platform == 'win32':
157 msg += '#install-imagemagick-on-windows'
158 elif sys.platform == 'darwin':
159 mac_pkgmgrs = {'brew': 'brew install freetype imagemagick',
160 'port': 'port install imagemagick'}
161 for pkgmgr in mac_pkgmgrs:
162 with os.popen('which ' + pkgmgr) as f:
163 if f.read().strip():
164 msg = mac_pkgmgrs[pkgmgr]
165 break
166 else:
167 msg += '#install-imagemagick-on-mac'
168 elif hasattr(platform, 'linux_distribution'):
169 distname, _, __ = platform.linux_distribution()
170 distname = (distname or '').lower()
171 if distname in ('debian', 'ubuntu'):
172 msg = 'apt-get install libmagickwand-dev'
173 elif distname in ('fedora', 'centos', 'redhat'):
174 msg = 'yum install ImageMagick-devel'
175 raise ImportError('MagickWand shared library not found.\n'
176 'You probably had not installed ImageMagick library.\n'
177 'Try to install:\n ' + msg)
179#: (:class:`ctypes.CDLL`) The MagickWand library.
180library = libraries[0]
182#: (:class:`ctypes.CDLL`) The ImageMagick library. It is the same with
183#: :data:`library` on platforms other than Windows.
184#:
185#: .. versionadded:: 0.1.10
186libmagick = libraries[1]
188try:
189 from wand.cdefs import (core, magick_wand, magick_image, magick_property,
190 pixel_iterator, pixel_wand, drawing_wand)
192 core.load(libmagick)
193 # Let's get the magick-version number to pass to load methods.
194 IM_VERSION = ctypes.c_size_t()
195 libmagick.GetMagickVersion(ctypes.byref(IM_VERSION))
196 # Query Quantum Depth (i.e. Q8, Q16, ... etc).
197 IM_QUANTUM_DEPTH = ctypes.c_size_t()
198 libmagick.GetMagickQuantumDepth(ctypes.byref(IM_QUANTUM_DEPTH))
199 # Does the library support HDRI?
200 IM_HDRI = 'HDRI' in str(libmagick.GetMagickFeatures())
201 core.load_with_version(libmagick, IM_VERSION.value)
202 magick_wand.load(library, IM_VERSION.value)
203 magick_property.load(library, IM_VERSION.value)
204 magick_image.load(library, IM_VERSION.value)
205 pixel_iterator.load(library, IM_VERSION.value)
206 pixel_wand.load(library, IM_VERSION.value, IM_QUANTUM_DEPTH.value, IM_HDRI)
207 drawing_wand.load(library, IM_VERSION.value)
208 del IM_HDRI, IM_QUANTUM_DEPTH, IM_VERSION
210except AttributeError:
211 raise ImportError('MagickWand shared library not found or incompatible\n'
212 'Original exception was raised in:\n' +
213 traceback.format_exc())
215#: (:class:`ctypes.CDLL`) The C standard library.
216libc = None
218if platform.system() == 'Windows':
219 msvcrt = ctypes.util.find_msvcrt()
220 # workaround -- the newest visual studio DLL is named differently:
221 if not msvcrt and '1900' in platform.python_compiler():
222 msvcrt = 'vcruntime140.dll'
223 if msvcrt:
224 libc = ctypes.CDLL(msvcrt)
225else:
226 libc_path = ctypes.util.find_library('c')
227 if libc_path:
228 libc = ctypes.cdll.LoadLibrary(libc_path)
229 else:
230 # Attempt to guess popular versions of libc
231 libc_paths = ('libc.so.6', 'libc.so', 'libc.a', 'libc.dylib',
232 '/usr/lib/libc.dylib')
233 for libc_path in libc_paths:
234 try:
235 libc = ctypes.cdll.LoadLibrary(libc_path)
236 break
237 except (IOError, OSError):
238 continue
239 if libc:
240 libc.fdopen.argtypes = [ctypes.c_int, ctypes.c_char_p]
241 libc.fdopen.restype = ctypes.c_void_p
242 libc.fflush.argtypes = [ctypes.c_void_p]