1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
use std::ffi::CString;
use std::mem;
use std::path::Path;
use std::slice;

use std::os::unix::prelude::*;

use libc::{EINVAL,ENOMEM};

/// The data type for raw pixel data.
pub type RawPixel = u16;

/// The data type for raw 3-color pixel data.
pub type Color3Pixel = [u16; 3];

/// The data type for raw 4-color pixel data.
pub type Color4Pixel = [u16; 4];

/// A raw image.
pub struct Image {
    data: *mut ::libraw::libraw_data_t,
}

impl Drop for Image {
    fn drop(&mut self) {
        unsafe {
            ::libraw::libraw_close(self.data);
        }
    }
}

impl Image {
    fn new() -> ::Result<Image> {
        let data = unsafe {
            ::libraw::libraw_init(::libraw::LIBRAW_OPIONS_NO_MEMERR_CALLBACK | ::libraw::LIBRAW_OPIONS_NO_DATAERR_CALLBACK)
        };

        if !data.is_null() {
            Ok(Image { data: data })
        }
        else {
            Err(::error::from_raw_os_error(ENOMEM))
        }
    }

    /// Opens the raw image file at the specified path.
    pub fn open(path: &Path) -> ::Result<Image> {
        let filename = match CString::new(path.as_os_str().as_bytes()) {
            Ok(s) => s,
            Err(_) => return Err(::error::from_raw_os_error(EINVAL))
        };

        let image = try!(Image::new());

        ::error::os::clear_errno();

        match unsafe { ::libraw::libraw_open_file(image.data, filename.as_ptr()) } {
            ::libraw::LIBRAW_SUCCESS => Ok(image),
            ::libraw::LIBRAW_IO_ERROR => {
                match ::error::os::errno() {
                    0 => Err(::error::from_libraw(::libraw::LIBRAW_IO_ERROR)),
                    errno => Err(::error::from_raw_os_error(errno)),
                }
            },
            err => Err(::error::from_libraw(err)),
        }
    }

    /// Unpacks the raw pixel data.
    ///
    /// The raw data must be unpacked before it can be accessed. After unpacking, the pixel type
    /// can be determined with `raw_pixel_type()`, and the pixel data can be accessed with
    /// `raw_pixmap()`, `color3_pixmap()`, or `color4_pixmap()`.
    pub fn unpack(&mut self) -> ::Result<()> {
        match unsafe { ::libraw::libraw_unpack(self.data) } {
            ::libraw::LIBRAW_SUCCESS => Ok(()),
            err => Err(::error::from_libraw(err)),
        }
    }

    /// Returns the pixel type of the raw data.
    ///
    /// The data must be unpacked before determining the pixel type. The value returned from this
    /// method determines which of the raw pixmap types is available.
    ///
    /// * `PixelType::Raw` means that `raw_pixmap()` is available.
    /// * `PixelType::Color3` means that `colro3_pixmap()` is available.
    /// * `PixelType::Color4` means that `colro4_pixmap()` is available.
    ///
    /// ## Errors
    ///
    /// This method returns an error if the pixel data has not been unpacked.
    pub fn raw_pixel_type(&self) -> ::Result<PixelType> {
        let rawdata = unsafe { &(*self.data).rawdata };

        if rawdata.raw_alloc.is_null() {
            return Err(::error::from_raw_os_error(EINVAL));
        }

        if !rawdata.raw_image.is_null() {
            return Ok(PixelType::Raw);
        }

        if !rawdata.color3_image.is_null() {
            return Ok(PixelType::Color3);
        }

        if !rawdata.color4_image.is_null() {
            return Ok(PixelType::Color4);
        }

        unreachable!();
    }

    /// Returns a pixmap of the raw pixels.
    ///
    /// ## Errors
    ///
    /// This method returns an error if the pixel data has not been unpacked or if the raw pixel
    /// data is in a different format (see `raw_pixel_type()`).
    pub fn raw_pixmap(&self) -> ::Result<Pixmap<RawPixel>> {
        let rawdata = unsafe { &(*self.data).rawdata };

        if !rawdata.raw_image.is_null() {
            let cols = rawdata.sizes.raw_width as usize;
            let rows = rawdata.sizes.raw_height as usize;

            Ok(Pixmap::new(rawdata.raw_image, cols, rows))
        }
        else {
            Err(::error::from_raw_os_error(EINVAL))
        }
    }

    /// Returns a pixmap of the raw 3-color pixels.
    ///
    /// ## Errors
    ///
    /// This method returns an error if the pixel data has not been unpacked or if the raw pixel
    /// data is in a different format (see `raw_pixel_type()`).
    pub fn color3_pixmap(&self) -> ::Result<Pixmap<Color3Pixel>> {
        let rawdata = unsafe { &(*self.data).rawdata };

        if !rawdata.raw_image.is_null() {
            let cols = rawdata.sizes.raw_width as usize;
            let rows = rawdata.sizes.raw_height as usize;

            Ok(Pixmap::new(rawdata.color3_image, cols, rows))
        }
        else {
            Err(::error::from_raw_os_error(EINVAL))
        }
    }

    /// Returns a pixmap of the raw 4-color pixels.
    ///
    /// ## Errors
    ///
    /// This method returns an error if the pixel data has not been unpacked or if the raw pixel
    /// data is in a different format (see `raw_pixel_type()`).
    pub fn color4_pixmap(&self) -> ::Result<Pixmap<Color4Pixel>> {
        let rawdata = unsafe { &(*self.data).rawdata };

        if !rawdata.raw_image.is_null() {
            let cols = rawdata.sizes.raw_width as usize;
            let rows = rawdata.sizes.raw_height as usize;

            Ok(Pixmap::new(rawdata.color4_image, cols, rows))
        }
        else {
            Err(::error::from_raw_os_error(EINVAL))
        }
    }
}

/// Types of raw pixel data.
pub enum PixelType {
    /// Each pixel is a single raw value, represented by the `RawPixel` type.
    Raw,

    /// Each pixel contains three color components, represented by the `Color3Pixel` type.
    Color3,

    /// Each pixel contains four color components, represented by the `Color4Pixel` type.
    Color4,
}

/// Maps pixel data onto a two-dimensional grid.
pub struct Pixmap<'a, T: Clone + 'static> {
    pixels: &'a [T],
    cols: usize,
    rows: usize,
}

impl<'a, T> Pixmap<'a, T> where T: Clone + 'static {
    fn new(ptr: *const T, cols: usize, rows: usize) -> Self {
        Pixmap {
            pixels: unsafe { slice::from_raw_parts(ptr, cols * rows) },
            cols: cols,
            rows: rows,
        }
    }

    /// Returns the number of columns.
    pub fn cols(&self) -> usize {
        self.cols
    }

    /// Returns the number of rows.
    pub fn rows(&self) -> usize {
        self.rows
    }

    /// Returns the number of pixels.
    pub fn len(&self) -> usize {
        self.pixels.len()
    }

    /// Returns an iterator over the pixels.
    pub fn pixels(&'a self) -> Pixels<'a, T> {
        Pixels::new(self)
    }
}

/// Iterates over pixels in a pixmap.
pub struct Pixels<'a, T: Clone + 'static> {
    pixmap: &'a Pixmap<'a, T>,
    cur: *const T,
    end: *const T,
}

impl<'a, T> Pixels<'a, T> where T: Clone + 'static {
    fn new(pixmap: &'a Pixmap<'a, T>) -> Self {
        Pixels {
            pixmap: pixmap,
            end: unsafe { pixmap.pixels.as_ptr().offset(pixmap.pixels.len() as isize) },
            cur: pixmap.pixels.as_ptr(),
        }
    }
}

impl<'a, T> Iterator for Pixels<'a, T> where T: Clone + 'static {
    type Item = Pixel<'a, T>;

    fn next(&mut self) -> Option<Pixel<'a, T>> {
        if self.cur < self.end {
            let pixel = Pixel::new(self);

            self.cur = unsafe { self.cur.offset(1) };

            Some(pixel)
        }
        else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let remaining = unsafe {
            let cur: usize = mem::transmute(self.cur);
            let end: usize = mem::transmute(self.end);

            end - cur
        };

        (remaining, Some(remaining))
    }
}

/// A reference to a pixel in a pixmap.
pub struct Pixel<'a, T: Clone + 'static> {
    pixmap: &'a Pixmap<'a, T>,
    pixel: *const T,
}

impl<'a, T> Pixel<'a, T> where T: Clone + 'static {
    fn new(pixels: &Pixels<'a, T>) -> Self {
        Pixel {
            pixmap: pixels.pixmap,
            pixel: pixels.cur,
        }
    }

    /// Returns the column of the pixel's location within the pixmap.
    pub fn col(&self) -> usize {
        self.index() % self.pixmap.cols()
    }

    /// Returns the row of the pixel's location within the pixmap.
    pub fn row(&self) -> usize {
        self.index() / self.pixmap.cols()
    }

    /// Returns the pixel's value.
    pub fn value(&self) -> T {
        let pixel: &T = unsafe { mem::transmute(self.pixel) };
        pixel.clone()
    }

    fn index(&self) -> usize {
        unsafe {
            let pixel: usize = mem::transmute(self.pixel);
            let start: usize = mem::transmute(self.pixmap.pixels.as_ptr());

            pixel - start
        }
    }
}