libopenraw 0.1.2

Rust API bindings for libopenraw
Documentation
/*
 * libopenraw-rs
 *
 * Copyright (C) 2021-2022 Hubert Figuière
 *
 * This library is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

use libopenraw_sys as ffi;

use super::Error;
use super::Result;
use crate::ifd;
use crate::ifd::Ifd;
use crate::thumbnail::Thumbnail;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum RawFileType {
    Unknown,
    Cr2,
    Crw,
    Nef,
    Mrw,
    Arw,
    Dng,
    Orf,
    Pef,
    Erf,
    Tiff,
    Nrw,
    Rw2,
    Raf,
    Cr3,
    Gpr,
    Sr2,
}

impl From<ffi::or_rawfile_type> for RawFileType {
    fn from(t: ffi::or_rawfile_type) -> RawFileType {
        use ffi::or_rawfile_type::*;
        match t {
            OR_RAWFILE_TYPE_UNKNOWN => Self::Unknown,
            OR_RAWFILE_TYPE_CR2 => Self::Cr2,
            OR_RAWFILE_TYPE_CRW => Self::Crw,
            OR_RAWFILE_TYPE_NEF => Self::Nef,
            OR_RAWFILE_TYPE_MRW => Self::Mrw,
            OR_RAWFILE_TYPE_ARW => Self::Arw,
            OR_RAWFILE_TYPE_DNG => Self::Dng,
            OR_RAWFILE_TYPE_ORF => Self::Orf,
            OR_RAWFILE_TYPE_PEF => Self::Pef,
            OR_RAWFILE_TYPE_ERF => Self::Erf,
            OR_RAWFILE_TYPE_TIFF => Self::Tiff,
            OR_RAWFILE_TYPE_NRW => Self::Nrw,
            OR_RAWFILE_TYPE_RW2 => Self::Rw2,
            OR_RAWFILE_TYPE_RAF => Self::Raf,
            OR_RAWFILE_TYPE_CR3 => Self::Cr3,
            OR_RAWFILE_TYPE_GPR => Self::Gpr,
            OR_RAWFILE_TYPE_SR2 => Self::Sr2,
        }
    }
}

impl From<RawFileType> for ffi::or_rawfile_type {
    fn from(t: RawFileType) -> Self {
        use ffi::or_rawfile_type::*;
        match t {
            RawFileType::Unknown => OR_RAWFILE_TYPE_UNKNOWN,
            RawFileType::Cr2 => OR_RAWFILE_TYPE_CR2,
            RawFileType::Crw => OR_RAWFILE_TYPE_CRW,
            RawFileType::Nef => OR_RAWFILE_TYPE_NEF,
            RawFileType::Mrw => OR_RAWFILE_TYPE_MRW,
            RawFileType::Arw => OR_RAWFILE_TYPE_ARW,
            RawFileType::Dng => OR_RAWFILE_TYPE_DNG,
            RawFileType::Orf => OR_RAWFILE_TYPE_ORF,
            RawFileType::Pef => OR_RAWFILE_TYPE_PEF,
            RawFileType::Erf => OR_RAWFILE_TYPE_ERF,
            RawFileType::Tiff => OR_RAWFILE_TYPE_TIFF,
            RawFileType::Nrw => OR_RAWFILE_TYPE_NRW,
            RawFileType::Rw2 => OR_RAWFILE_TYPE_RW2,
            RawFileType::Raf => OR_RAWFILE_TYPE_RAF,
            RawFileType::Cr3 => OR_RAWFILE_TYPE_CR3,
            RawFileType::Gpr => OR_RAWFILE_TYPE_GPR,
            RawFileType::Sr2 => OR_RAWFILE_TYPE_SR2,
        }
    }
}

pub struct RawFile(ffi::ORRawFileRef);

impl RawFile {
    /// Open `RawFile` from `filename`, eventually hinted by `type_`.
    pub fn from_file<P: AsRef<std::path::Path>>(filename: P, type_: RawFileType) -> Result<Self> {
        let cstr = crate::utils::path_to_filename(filename);
        let rf = unsafe { ffi::or_rawfile_new(cstr.as_ptr(), type_.into()) };
        if rf.is_null() {
            Err(Error::CantOpen)
        } else {
            Ok(Self(rf))
        }
    }

    /// Open `RawFile` from a memory buffer.
    pub fn from_memory(buffer: &[u8], type_: RawFileType) -> Result<Self> {
        let rf = unsafe {
            ffi::or_rawfile_new_from_memory(buffer.as_ptr(), buffer.len() as u32, type_.into())
        };
        if rf.is_null() {
            Err(Error::CantOpen)
        } else {
            Ok(Self(rf))
        }
    }

    /// Get the Exif orientation. The value match the Exif values.
    pub fn get_orientation(&self) -> i32 {
        unsafe { ffi::or_rawfile_get_orientation(self.0) }
    }

    /// Get the thumbnail with `preferred_size`.
    pub fn get_thumbnail(&self, preferred_size: u32) -> Result<Thumbnail> {
        let thumbnail = Thumbnail::new();
        let error = unsafe { ffi::or_rawfile_get_thumbnail(self.0, preferred_size, thumbnail.0) };
        if error != ffi::or_error::OR_ERROR_NONE {
            Err(error.into())
        } else {
            Ok(thumbnail)
        }
    }

    /// Get an image file directory of type `ifd_type`.
    pub fn get_ifd(&self, ifd_type: ifd::DirType) -> ifd::Ifd {
        Ifd::new(unsafe { ffi::or_rawfile_get_ifd(self.0, ifd_type.into()) })
    }
}

impl Drop for RawFile {
    fn drop(&mut self) {
        unsafe {
            ffi::or_rawfile_release(self.0);
        }
    }
}