1""":mod:`libraw.bindings` --- Low-level LibRaw bindings
2~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3
4The :class:`libraw.bindings` module handles linking against the LibRaw binary.
5"""
6
7from ctypes import *  # noqa
8from ctypes import util
9
10from libraw import errors
11from libraw.callbacks import data_callback
12from libraw.callbacks import memory_callback
13from libraw.callbacks import progress_callback
14from libraw.errors import c_error
15from libraw import structs_16
16from libraw import structs_17
17from libraw import structs_18
18
19
20class LibRaw(CDLL):
21
22    """
23    A :class:`ctypes.CDLL` that links against `libraw.so` (or the equivalent on
24    your platform).
25
26    Raises:
27        ImportError: If LibRaw cannot be found on your system, or linking
28                     fails.
29    """
30
31    def __init__(self):  # pragma: no cover
32        libraw = util.find_library('raw')
33        try:
34            if libraw is not None:
35                super(LibRaw, self).__init__(libraw)
36            else:
37                raise ImportError
38        except (ImportError, AttributeError, OSError, IOError):
39            raise ImportError('Cannot find LibRaw on your system!')
40
41        try:
42            structs = {
43                16: structs_16,
44                17: structs_17,
45                18: structs_18,
46            }[self.version_number[1]]
47        except KeyError:
48            raise ImportError(
49                'Unsupported Libraw version: %s.%s.%s.' % self.version_number
50            )
51
52        libraw_data_t = structs.libraw_data_t
53        libraw_decoder_info_t = structs.libraw_decoder_info_t
54        libraw_processed_image_t = structs.libraw_processed_image_t
55
56        # Define arg types
57
58        self.libraw_init.argtypes = [c_int]
59        # enum LibRaw_progress
60        self.libraw_strprogress.argtypes = [c_int]
61        self.libraw_unpack_function_name.argtypes = [POINTER(libraw_data_t)]
62
63        self.libraw_subtract_black.argtypes = [POINTER(libraw_data_t)]
64        self.libraw_open_file.argtypes = [POINTER(libraw_data_t), c_char_p]
65        self.libraw_open_file_ex.argtypes = [
66            POINTER(libraw_data_t),
67            c_char_p,
68            c_int64
69        ]
70        self.libraw_open_buffer.argtypes = [
71            POINTER(libraw_data_t),
72            c_void_p,
73            c_int64
74        ]
75        self.libraw_unpack.argtypes = [POINTER(libraw_data_t)]
76        self.libraw_unpack_thumb.argtypes = [POINTER(libraw_data_t)]
77        self.libraw_recycle_datastream.argtypes = [POINTER(libraw_data_t)]
78        self.libraw_recycle.argtypes = [POINTER(libraw_data_t)]
79        self.libraw_close.argtypes = [POINTER(libraw_data_t)]
80        self.libraw_set_memerror_handler.argtypes = [
81            POINTER(libraw_data_t),
82            memory_callback,
83            c_void_p,
84        ]
85        self.libraw_set_dataerror_handler.argtypes = [
86            POINTER(libraw_data_t),
87            data_callback,
88            c_void_p,
89        ]
90        self.libraw_set_progress_handler.argtypes = [
91            POINTER(libraw_data_t),
92            progress_callback,
93            c_void_p,
94        ]
95        self.libraw_adjust_sizes_info_only.argtypes = [
96            POINTER(libraw_data_t)
97        ]
98        self.libraw_dcraw_ppm_tiff_writer.argtypes = [
99            POINTER(libraw_data_t),
100            c_char_p
101        ]
102        self.libraw_dcraw_thumb_writer.argtypes = [
103            POINTER(libraw_data_t),
104            c_char_p
105        ]
106        self.libraw_dcraw_process.argtypes = [POINTER(libraw_data_t)]
107        self.libraw_dcraw_make_mem_image.argtypes = [
108            POINTER(libraw_data_t),
109            POINTER(c_int)
110        ]
111        self.libraw_dcraw_make_mem_thumb.argtypes = [
112            POINTER(libraw_data_t),
113            POINTER(c_int)
114        ]
115        self.libraw_dcraw_clear_mem.argtypes = [
116            POINTER(libraw_processed_image_t)
117        ]
118        self.libraw_raw2image.argtypes = [POINTER(libraw_data_t)]
119        self.libraw_free_image.argtypes = [POINTER(libraw_data_t)]
120        self.libraw_get_decoder_info.argtypes = [
121            POINTER(libraw_data_t),
122            POINTER(libraw_decoder_info_t)
123        ]
124        self.libraw_COLOR.argtypes = [
125            POINTER(libraw_data_t),
126            c_int,
127            c_int
128        ]
129
130        # Define return types
131
132        self.libraw_init.restype = POINTER(libraw_data_t)
133        self.libraw_version.restype = c_char_p
134        self.libraw_strprogress.restype = c_char_p
135        self.libraw_versionNumber.restype = c_int
136        self.libraw_cameraCount.restype = c_int
137        self.libraw_cameraList.restype = POINTER(
138            c_char_p * self.libraw_cameraCount()
139        )
140        self.libraw_unpack_function_name.restype = c_char_p
141        self.libraw_subtract_black.restype = POINTER(libraw_data_t)
142        self.libraw_open_file.restype = c_error
143        self.libraw_open_file_ex.restype = c_error
144        self.libraw_open_buffer.restype = c_error
145        self.libraw_unpack.restype = c_error
146        self.libraw_unpack_thumb.restype = c_error
147        self.libraw_adjust_sizes_info_only.restype = c_error
148        self.libraw_dcraw_ppm_tiff_writer.restype = c_error
149        self.libraw_dcraw_thumb_writer.restype = c_error
150        self.libraw_dcraw_process.restype = c_error
151        self.libraw_dcraw_make_mem_image.restype = POINTER(
152            libraw_processed_image_t)
153        self.libraw_dcraw_make_mem_thumb.restype = POINTER(
154            libraw_processed_image_t)
155        self.libraw_raw2image.restype = c_error
156        self.libraw_get_decoder_info.restype = c_error
157        self.libraw_COLOR.restype = c_int
158
159        # Some special Windows-only garbage:
160
161        try:
162            self.libraw_open_wfile.argtypes = [
163                POINTER(libraw_data_t),
164                c_wchar_p
165            ]
166            self.libraw_open_wfile_ex.argtypes = [
167                POINTER(libraw_data_t),
168                c_wchar_p,
169                c_int64
170            ]
171            self.libraw_open_wfile.restype = c_error
172            self.libraw_open_wfile_ex.restype = c_error
173        except AttributeError:
174            pass
175
176    @property
177    def version_number(self):
178        """
179        A numeric representation of the version of LibRaw which we have linked
180        against in ``(Major, Minor, Patch)`` form. eg. ::
181
182            (0, 16, 1)
183
184        Returns:
185            3 tuple: The version number
186        """
187        v = self.libraw_versionNumber()
188        return ((v >> 16) & 0x0000ff, (v >> 8) & 0x0000ff, v & 0x0000ff)
189
190    @property
191    def version(self):
192        """
193        A string representation of the version of LibRaw which we have linked
194        against. eg. ::
195
196            "0.16.1-Release"
197
198        Returns:
199            str: The version
200        """
201        return self.libraw_version().decode('utf-8')
202
203    def __getitem__(self, name):
204        func = super(LibRaw, self).__getitem__(name)
205
206        func.errcheck = errors.check_call
207
208        return func
209