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
use super::*;

extern crate lcms2_sys as ffi;

use std;
use std::os::raw::c_void;
use std::marker::PhantomData;

impl<F: Copy + Clone, T: Copy + Clone> Transform<F, T> {
    pub fn new(input: &Profile,
               in_format: PixelFormat,
               output: &Profile,
               out_format: PixelFormat,
               intent: Intent) -> Transform<F, T> {
        Self::new_flags(input, in_format, output, out_format, intent, 0)
    }

    pub fn new_flags(input: &Profile,
                     in_format: PixelFormat,
                     output: &Profile,
                     out_format: PixelFormat,
                     intent: Intent,
                     flags: u32)
                     -> Transform<F, T> {
        Self::new_handle(unsafe {
                             ffi::cmsCreateTransform(input.handle,
                                                     in_format,
                                                     output.handle,
                                                     out_format,
                                                     intent,
                                                     flags)
                         },
                         in_format,
                         out_format)
    }

    pub fn new_proofing(input: &Profile,
                        in_format: PixelFormat,
                        output: &Profile,
                        out_format: PixelFormat,
                        proofing: &Profile,
                        intent: Intent,
                        proofng_intent: Intent,
                        flags: u32)
                        -> Transform<F, T> {
        Self::new_handle(unsafe {
                             ffi::cmsCreateProofingTransform(input.handle,
                                                             in_format,
                                                             output.handle,
                                                             out_format,
                                                             proofing.handle,
                                                             intent,
                                                             proofng_intent,
                                                             flags)
                         },
                         in_format,
                         out_format)
    }

    fn new_handle(handle: ffi::HTRANSFORM, in_format: PixelFormat, out_format: PixelFormat) -> Transform<F, T> {
        assert!(!handle.is_null());
        Transform {
            handle: handle,
            _from: Self::check_format::<F>(in_format),
            _to: Self::check_format::<T>(out_format),
        }
    }

    fn check_format<Z>(format: PixelFormat) -> PhantomData<Z> {
        assert!(!format.planar(), "Planar not supported");
        assert_eq!(format.bytes_per_pixel(),
                   std::mem::size_of::<Z>(),
                   "PixelFormat {:?} has different size than the Rust data type",
                   format);
        PhantomData
    }

    pub fn transform_pixels(&self, src: &[F], dst: &mut [T]) {
        let size = src.len();
        assert_eq!(size, dst.len());
        assert!(size < std::u32::MAX as usize);
        unsafe {
            ffi::cmsDoTransform(self.handle,
                                src.as_ptr() as *const c_void,
                                dst.as_ptr() as *mut c_void,
                                size as u32);
        }
    }

    pub fn input_format(&self) -> PixelFormat {
        unsafe { ffi::cmsGetTransformInputFormat(self.handle) as PixelFormat }
    }

    pub fn output_format(&self) -> PixelFormat {
        unsafe { ffi::cmsGetTransformOutputFormat(self.handle) as PixelFormat }
    }
}

impl<T: Copy + Clone> Transform<T, T> {
    pub fn transform_in_place(&self, srcdst: &mut [T]) {
        let size = srcdst.len();
        assert!(size < std::u32::MAX as usize);
        unsafe {
            ffi::cmsDoTransform(self.handle,
                                srcdst.as_ptr() as *const c_void,
                                srcdst.as_ptr() as *mut c_void,
                                size as u32);
        }
    }
}

impl<F, T> Drop for Transform<F, T> {
    fn drop(&mut self) {
        unsafe {
            ffi::cmsDeleteTransform(self.handle);
        }
    }
}