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
//! Minimal Crate for reading and manipulating `NITF` files
//! Interface for NITF version 2.1
//!
//! Constructing a [Nitf] object parses the header and subheader information.
//! Each segment in contains a `meta` field which stores the respective
//! fields defined in the file standard. The primary function for constructing a
//! [Nitf] is [read_nitf()]
//! ```no_run
//! // Read a nitf file and dump metadata to stdout
//! use std::path::Path;
//! let nitf_path = Path::new("../example.nitf");
//! let nitf = nitf_rs::read_nitf(&nitf_path).unwrap();
//! println!("{nitf:?}");
//! ```
//!
//! The main feature of the [FileHeader] is its `meta` field (see (NitfHeader)
//! [headers::NitfHeader]).
//! All other segments use the generic [NitfSegment] to provide header fields and
//! a memory-map of the segment data.
//! ```no_run
//! // Get the bytes from the first image segment
//! use std::path::Path;
//! let nitf_path = Path::new("../example.nitf");
//! let nitf = nitf_rs::read_nitf(&nitf_path).unwrap();
//! let im_seg = &nitf.image_segments[0];
//! let u8_slice = &im_seg.data[..];
//! ```
//! Most metadata elements are stored in a [NitfField] structure. This structure
//! stores the `bytes` which encode the value, a `string` representation, and a
//! `val` which holds on to native value of the field (i.e., the bytes parsed into a
//! u8, u16, String, enum, etc.)
//! ```no_run
//! // Read in a nitf and extract the...
//! use std::path::Path;
//! let nitf_path = Path::new("../example.nitf");
//! let nitf = nitf_rs::read_nitf(&nitf_path).unwrap();
//! // .. File title
//! let file_title = nitf.nitf_header.meta.ftitle.val;
//! // .. Number of image segments
//! let n_img_segments = nitf.nitf_header.meta.numi.val;
//! // .. and number of rows in the first image segment data
//! let n_rows = nitf.image_segments[0].meta.nrows.val;
//! ```
//!
//! If there is user-defined tagged-record-extension (TRE) data within a segment,
//! it is stored in an [ExtendedSubheader] for the user to parse accordingly.
use log::debug;
use std::fmt::Display;
use std::fs::File;
use std::path::Path;
use thiserror::Error;
pub type NitfResult<T> = Result<T, NitfError>;
#[derive(Error, Debug)]
pub enum NitfError {
// Crate specific errors
#[error("File does not appear to be a NITF. Expected file header \"NITF\", found \"{0}\"")]
FileType(String),
#[error("error parsing {0} enum")]
EnumError(&'static str),
#[error("Fatal error reading {0}")]
Fatal(String),
// Wrappers for built in errors
#[error(transparent)]
IOError(#[from] std::io::Error),
}
pub mod headers;
pub mod segments;
pub mod types;
// Convenience type-defs
use segments::NitfSegment;
type ImageSegment = NitfSegment<headers::ImageHeader>;
type GraphicSegment = NitfSegment<headers::GraphicHeader>;
type TextSegment = NitfSegment<headers::TextHeader>;
type DataExtensionSegment = NitfSegment<headers::DataExtensionHeader>;
type ReservedExtensionSegment = NitfSegment<headers::ReservedExtensionHeader>;
use segments::FileHeader;
#[allow(unused_imports)]
use types::{ExtendedSubheader, NitfField};
/// Top level NITF interface
#[derive(Default, Debug, Eq, PartialEq)]
pub struct Nitf {
/// Nitf file header.
pub nitf_header: FileHeader,
/// Vector of image segments.
pub image_segments: Vec<ImageSegment>,
/// Vector of graphics segments.
pub graphic_segments: Vec<GraphicSegment>,
/// Vector of text segments.
pub text_segments: Vec<TextSegment>,
/// Vector of data extension segments.
pub data_extension_segments: Vec<DataExtensionSegment>,
/// Vector of reserved extension segments.
pub reserved_extension_segments: Vec<ReservedExtensionSegment>,
}
/// Construct a [Nitf] object from a file `path`.
///
/// # Example
/// ```no_run
/// use std::path::Path;
/// let nitf_path = Path::new("../example.nitf");
/// let nitf = nitf_rs::read_nitf(nitf_path).unwrap();
/// ```
pub fn read_nitf(path: &Path) -> NitfResult<Nitf> {
// Crash if failure to open file
let mut file = File::open(path)?;
Nitf::from_file(&mut file)
}
impl Nitf {
pub fn from_file(file: &mut File) -> NitfResult<Self> {
let mut nitf = Self::default();
debug!("Reading NITF file header");
nitf.nitf_header.read(file)?;
let mut n_seg = nitf.nitf_header.meta.numi.val as usize;
for i_seg in 0..n_seg {
let seg_info = &nitf.nitf_header.meta.imheaders[i_seg];
let header_size = seg_info.subheader_size.val;
let data_size = seg_info.item_size.val;
let seg = ImageSegment::initialize(file, header_size, data_size)?;
nitf.image_segments.push(seg);
}
n_seg = nitf.nitf_header.meta.nums.val as usize;
for i_seg in 0..n_seg {
let seg_info = &nitf.nitf_header.meta.graphheaders[i_seg];
let header_size = seg_info.subheader_size.val;
let data_size: u64 = seg_info.item_size.val;
let seg = GraphicSegment::initialize(file, header_size, data_size)?;
nitf.graphic_segments.push(seg);
}
n_seg = nitf.nitf_header.meta.numt.val as usize;
for i_seg in 0..n_seg {
let seg_info = &nitf.nitf_header.meta.textheaders[i_seg];
let header_size = seg_info.subheader_size.val;
let data_size: u64 = seg_info.item_size.val;
let seg = TextSegment::initialize(file, header_size, data_size)?;
nitf.text_segments.push(seg);
}
n_seg = nitf.nitf_header.meta.numdes.val as usize;
for i_seg in 0..n_seg {
let seg_info = &nitf.nitf_header.meta.dextheaders[i_seg];
let header_size = seg_info.subheader_size.val;
let data_size: u64 = seg_info.item_size.val;
let seg = DataExtensionSegment::initialize(file, header_size, data_size)?;
nitf.data_extension_segments.push(seg);
}
n_seg = nitf.nitf_header.meta.numres.val as usize;
for i_seg in 0..n_seg {
let seg_info = &nitf.nitf_header.meta.resheaders[i_seg];
let header_size = seg_info.subheader_size.val;
let data_size = seg_info.item_size.val;
let seg = ReservedExtensionSegment::initialize(file, header_size, data_size)?;
nitf.reserved_extension_segments.push(seg);
}
Ok(nitf)
}
}
impl Display for Nitf {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let mut out_str = String::default();
out_str += format!("{}", self.nitf_header).as_ref();
for segment in &self.image_segments {
out_str += format!("{}", segment).as_ref();
}
for segment in &self.graphic_segments {
out_str += format!("{}", segment).as_ref();
}
for segment in &self.text_segments {
out_str += format!("{}", segment).as_ref();
}
for segment in &self.data_extension_segments {
out_str += format!("{}", segment).as_ref();
}
for segment in &self.reserved_extension_segments {
out_str += format!("{}", segment).as_ref();
}
write!(f, "{}", out_str)
}
}