Add parse_image(), which accepts a JPEG or TIFF image.

This commit is contained in:
KAMADA Ken'ichi 2017-01-12 21:51:11 +09:00
parent e5ffcb23c4
commit 906a25cb31
4 changed files with 77 additions and 3 deletions

59
src/image.rs Normal file
View File

@ -0,0 +1,59 @@
//
// Copyright (c) 2016 KAMADA Ken'ichi.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
use std::io;
use std::io::Read;
use std::mem;
use error::Error;
use jpeg;
use tiff;
use tiff::Field;
/// Parse the Exif attributes in a JPEG or TIFF image data.
///
/// Returns a Vec of Exif fields and a bool.
/// The boolean value is true if the data is little endian.
/// If an error occurred, `exif::Error` is returned.
///
/// The `buf` must be an empty `Vec<u8>` when this function is called.
/// The raw Exif data is read into it.
pub fn parse_image<'a, R>(mut reader: &mut R, mut buf: &'a mut Vec<u8>)
-> Result<(Vec<Field<'a>>, bool), Error>
where R: io::BufRead
{
try!(reader.by_ref().take(4).read_to_end(buf));
if jpeg::is_jpeg(buf) {
let exif_buf = try!(jpeg::get_exif_attr(
&mut buf.as_mut_slice().chain(reader)));
mem::replace(buf, exif_buf);
} else if tiff::is_tiff(buf) {
try!(reader.read_to_end(&mut buf));
} else {
return Err(Error::InvalidFormat("Unknown image format"));
}
tiff::parse_exif(buf)
}

View File

@ -45,6 +45,9 @@ mod marker {
pub const APP1: u8 = 0xe1;
}
// SOI marker as the JPEG header.
const JPEG_SIG: [u8; 2] = [marker::P, marker::SOI];
// Exif identifier code "Exif\0\0". [EXIF23 4.7.2]
const EXIF_ID: [u8; 6] = [0x45, 0x78, 0x69, 0x66, 0x00, 0x00];
@ -99,6 +102,10 @@ fn get_exif_attr_sub<R>(reader: &mut R)
}
}
pub fn is_jpeg(buf: &[u8]) -> bool {
buf.starts_with(&JPEG_SIG)
}
#[cfg(test)]
mod tests {
use std::io::Cursor;

View File

@ -28,19 +28,20 @@
//!
//! # Examples
//!
//! An example to parse a JPEG file:
//! An example to parse a JPEG/TIFF file:
//!
//! ```
//! let file = std::fs::File::open("tests/exif.jpg").unwrap();
//! let mut reader = std::io::BufReader::new(&file);
//! let buf = exif::get_exif_attr_from_jpeg(&mut reader).unwrap();
//! let (fields, _) = exif::parse_exif(&buf).unwrap();
//! let mut buf = Vec::new();
//! let (fields, _) = exif::parse_image(&mut reader, &mut buf).unwrap();
//! for f in fields {
//! println!("{} {} {:?}", f.tag, f.thumbnail, f.value);
//! }
//! ```
pub use error::Error;
pub use image::parse_image;
pub use jpeg::get_exif_attr as get_exif_attr_from_jpeg;
pub use tag::{Context, Tag};
pub use tiff::Field;
@ -54,6 +55,7 @@ mod tmacro;
mod endian;
mod error;
mod image;
mod jpeg;
pub mod tag;
mod tiff;

View File

@ -35,6 +35,8 @@ use value::get_type_info;
const TIFF_BE: u16 = 0x4d4d;
const TIFF_LE: u16 = 0x4949;
const TIFF_FORTY_TWO: u16 = 0x002a;
const TIFF_BE_SIG: [u8; 4] = [0x4d, 0x4d, 0x00, 0x2a];
const TIFF_LE_SIG: [u8; 4] = [0x49, 0x49, 0x2a, 0x00];
/// A TIFF field.
#[derive(Debug)]
@ -149,6 +151,10 @@ fn parse_ifd<E>(data: &[u8], offset: usize, ctx: Context, thumbnail: bool)
Ok(fields)
}
pub fn is_tiff(buf: &[u8]) -> bool {
buf.starts_with(&TIFF_BE_SIG) || buf.starts_with(&TIFF_LE_SIG)
}
#[cfg(test)]
mod tests {
use error::Error;