nitf_rs/headers/
image_hdr.rs

1//! Image segment definition
2//!
3//! This is by far the most complicated part of the interface, and requires
4//! a lot of manual action to setup properly. Future work will hopefully be done
5//! to smooth out the process
6use std::fmt::Display;
7use std::io::{Read, Seek, Write};
8use std::str::FromStr;
9
10use crate::headers::NitfSegmentHeader;
11use crate::types::{ExtendedSubheader, NitfField, Security};
12use crate::{NitfError, NitfResult};
13
14/// Metadata for Image Segment subheader
15#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
16pub struct ImageHeader {
17    /// File Part Type
18    pub im: NitfField<IM>,
19    /// Image Identifier 1
20    pub iid1: NitfField<String>,
21    /// Image Date and Time
22    pub idatim: NitfField<String>,
23    /// Target Identifier
24    pub tgtid: NitfField<String>,
25    /// Image Identifier 2
26    pub iid2: NitfField<String>,
27    /// Security information
28    pub security: Security,
29    /// Encryption
30    pub encryp: NitfField<String>,
31    /// Image Source
32    pub isorce: NitfField<String>,
33    /// Number of Significant Rows in image
34    pub nrows: NitfField<u32>,
35    /// Number of Significant Columns in image
36    pub ncols: NitfField<u32>,
37    /// Pixel Value Type
38    pub pvtype: NitfField<PixelValueType>,
39    /// Image Representation
40    pub irep: NitfField<ImageRepresentation>,
41    /// Image Category
42    pub icat: NitfField<String>,
43    /// Actual Bits-Per-Pixel Per Band
44    pub abpp: NitfField<u8>,
45    /// Pixel Justification
46    pub pjust: NitfField<PixelJustification>,
47    /// Image Coordinate Representation
48    pub icords: NitfField<CoordinateRepresentation>,
49    /// Image Geographic Location
50    pub igeolo: NitfField<String>,
51    /// Number of Image Comments
52    pub nicom: NitfField<u8>,
53    /// Image Comments
54    pub icoms: Vec<NitfField<String>>,
55    /// Image Compression
56    pub ic: NitfField<Compression>,
57    /// Compression Rate Code
58    pub comrat: NitfField<String>,
59    /// Number of Bands
60    pub nbands: NitfField<u8>,
61    /// Number of Multispectral Bands
62    pub xbands: NitfField<u32>,
63    /// Data bands
64    pub bands: Vec<Band>,
65    /// Image Sync Code
66    pub isync: NitfField<u8>,
67    /// Image Mode
68    pub imode: NitfField<Mode>,
69    /// Number of Blocks per Row
70    pub nbpr: NitfField<u16>,
71    /// Number of Blocks per Column
72    pub nbpc: NitfField<u16>,
73    /// Number of Pixels Per Block Horizontal
74    pub nppbh: NitfField<u16>,
75    /// Number of Pixels Per Block Vertical
76    pub nppbv: NitfField<u16>,
77    /// Number of Bits Per Pixel
78    pub nbpp: NitfField<u8>,
79    /// Image Display Level
80    pub idlvl: NitfField<u16>,
81    /// Image Attachment Level
82    pub ialvl: NitfField<u16>,
83    /// Image Location
84    pub iloc: NitfField<String>,
85    /// Image Magnification
86    pub imag: NitfField<String>,
87    /// User Defined Image Data Length
88    pub udidl: NitfField<u32>,
89    /// User Defined Overflow
90    pub udofl: NitfField<u16>,
91    /// User Defined Image Data
92    pub udid: ExtendedSubheader,
93    /// Image Extended Subheader Data Length
94    pub ixshdl: NitfField<u32>,
95    /// Image Extended Subheader Overflow
96    pub ixsofl: NitfField<u16>,
97    /// Image Extended Subheader Data
98    pub ixshd: ExtendedSubheader,
99}
100impl Default for ImageHeader {
101    fn default() -> Self {
102        Self {
103            im: NitfField::init(2u8, "IM"),
104            iid1: NitfField::init(10u8, "IID1"),
105            idatim: NitfField::init(14u8, "IDATIM"),
106            tgtid: NitfField::init(17u8, "TGTID"),
107            iid2: NitfField::init(80u8, "IID2"),
108            security: Security::default(),
109            encryp: NitfField::init(1u8, "ENCRYP"),
110            isorce: NitfField::init(42u8, "ISORCE"),
111            nrows: NitfField::init(8u8, "NROWS"),
112            ncols: NitfField::init(8u8, "NCOLS"),
113            pvtype: NitfField::init(3u8, "PVTYPE"),
114            irep: NitfField::init(8u8, "IREP"),
115            icat: NitfField::init(8u8, "ICAT"),
116            abpp: NitfField::init(2u8, "ABPP"),
117            pjust: NitfField::init(1u8, "PJUST"),
118            icords: NitfField::init(1u8, "ICORDS"),
119            igeolo: NitfField::init(60u8, "IGEOLO"),
120            nicom: NitfField::init(1u8, "NICOM"),
121            icoms: vec![],
122            ic: NitfField::init(2u8, "IC"),
123            comrat: NitfField::init(4u8, "COMRAT"),
124            nbands: NitfField::init(1u8, "NBANDS"),
125            xbands: NitfField::init(5u8, "XBANDS"),
126            bands: vec![],
127            isync: NitfField::init(1u8, "ISYNC"),
128            imode: NitfField::init(1u8, "IMODE"),
129            nbpr: NitfField::init(4u8, "NBPR"),
130            nbpc: NitfField::init(4u8, "NBPC"),
131            nppbh: NitfField::init(4u8, "NPPBH"),
132            nppbv: NitfField::init(4u8, "NPPBV"),
133            nbpp: NitfField::init(2u8, "NBPP"),
134            idlvl: NitfField::init(3u8, "IDLVL"),
135            ialvl: NitfField::init(3u8, "IALVL"),
136            iloc: NitfField::init(10u8, "ILOC"),
137            imag: NitfField::init(4u8, "IMAG"),
138            udidl: NitfField::init(5u8, "UDIDL"),
139            udofl: NitfField::init(3u8, "UDOFL"),
140            udid: ExtendedSubheader::init("UDID"),
141            ixshdl: NitfField::init(5u8, "IXSHDL"),
142            ixsofl: NitfField::init(3u8, "IXSOFL"),
143            ixshd: ExtendedSubheader::init("IXSHD"),
144        }
145    }
146}
147
148#[derive(Default, Clone, Debug, Eq, PartialEq, Copy, Ord, PartialOrd)]
149pub enum IM {
150    #[default]
151    IM,
152}
153impl FromStr for IM {
154    type Err = NitfError;
155    fn from_str(s: &str) -> Result<Self, Self::Err> {
156        match s {
157            "IM" => Ok(Self::default()),
158            _ => Err(NitfError::ParseError("IM".to_string())),
159        }
160    }
161}
162impl Display for IM {
163    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164        write!(f, "IM")
165    }
166}
167
168/// Band metadata
169///
170/// If there is look-up-table (LUT) data, is is stored as a `Vec<Vec<u8>>`
171#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
172pub struct Band {
173    /// Band Representation
174    pub irepband: NitfField<ImageRepresentationBand>,
175    /// Band Subcategory
176    pub isubcat: NitfField<String>, // User specified
177    /// Band Image Filter Condition
178    pub ifc: NitfField<ImageFilterCondition>, // Reserved for future use
179    /// Band Standard Image Filter Code
180    pub imflt: NitfField<String>, // Reserved for future use
181    /// Number of Look-Up-Tables for the Image Band
182    pub nluts: NitfField<u8>, //
183    /// Number of Look-Up-Table Entries for the Image Band
184    pub nelut: NitfField<u16>,
185    /// Image Band Look-Up-Tables
186    pub lutd: Vec<Vec<u8>>,
187}
188impl Default for Band {
189    fn default() -> Self {
190        Self {
191            irepband: NitfField::init(2u8, "IREPBAND"),
192            isubcat: NitfField::init(6u8, "ISUBCAT"),
193            ifc: NitfField::init(1u8, "IFC"),
194            imflt: NitfField::init(3u8, "IMFLT"),
195            nluts: NitfField::init(1u8, "NLUTS"),
196            nelut: NitfField::init(5u8, "NELUT"),
197            lutd: vec![],
198        }
199    }
200}
201impl Band {
202    pub fn length(&self) -> usize {
203        let mut length = 0;
204        length += self.irepband.length;
205        length += self.isubcat.length;
206        length += self.ifc.length;
207        length += self.imflt.length;
208        length += self.nluts.length;
209        if self.nluts.val != 0 {
210            length += self.nelut.length;
211            // Each LUT element is one byte
212            length += (self.nelut.val * self.nluts.val as u16) as usize;
213        }
214        length
215    }
216}
217
218/// Pixel Value type options
219#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
220pub enum PixelValueType {
221    #[default]
222    /// ComplexFloat, 32 or 64 bits, real then imaginary
223    C,
224    /// Float, 32 or 64 bits
225    R,
226    /// Bi-level, single bit
227    B,
228    /// 2's complement signed integer, 8, 12, 16, 32, or 64 bits
229    SI,
230    /// Integer, 8, 12, 16, 32, or 64 bits
231    INT,
232}
233
234/// Image representation values
235#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
236pub enum ImageRepresentation {
237    #[default]
238    /// Monochrome
239    MONO,
240    /// RGB true color
241    RGB,
242    /// RGB/LUT for mapped color
243    RGBLUT,
244    /// Multiband imagery
245    MULTI,
246    /// Not intended for display
247    NODISPLY,
248    /// Vectors with cartesian coordinates
249    NVECTOR,
250    /// Vectors with polar coordinates
251    POLAR,
252    /// SAR video phase history
253    VPH,
254    /// Compressed in the ITU-R recommendation
255    YCbCr601,
256}
257/// Image representation values
258#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
259pub enum ImageRepresentationBand {
260    #[default]
261    /// Default spaces
262    DEFAULT,
263    /// Monochrome
264    M,
265    /// RGB
266    R,
267    G,
268    B,
269    /// LUT Reperesentation
270    LU,
271    /// Luminance
272    Y,
273    /// Chrominance Blue
274    Cb,
275    /// Chrominance Red
276    Cr,
277}
278#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
279pub enum ImageFilterCondition {
280    #[default]
281    /// None
282    N,
283}
284
285/// Pixel justification
286#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
287pub enum PixelJustification {
288    #[default]
289    /// Right justified
290    R,
291    /// Left justified
292    L,
293}
294
295/// Coordinate representation
296#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
297pub enum CoordinateRepresentation {
298    #[default]
299    /// Default value, one space
300    DEFAULT,
301    /// UTM in Military Grid Reference System
302    U,
303    /// UTM/UPS Northern hemisphere
304    N,
305    /// UTM/UPS Southern hemisphere
306    S,
307    /// UPS
308    P,
309    /// Geographic
310    G,
311    /// Decimal degrees
312    D,
313}
314
315/// Image compression values
316#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
317pub enum Compression {
318    #[default]
319    /// Not compressed
320    NC,
321    /// Uncompressed, contains mask
322    NM,
323    /// Bi-level
324    C1,
325    /// JPEG
326    C3,
327    /// Vector Quantization
328    C4,
329    /// Lossless JPEG
330    C5,
331    /// Reserved for future compression algorithm
332    C6,
333    /// Resrved for future complex SAR compression
334    C7,
335    /// ISO JPEG 2000
336    C8,
337    /// Downsampled JPEG
338    I1,
339    /// Compressed, contains mask
340    M1,
341    /// Compressed, contains mask
342    M3,
343    /// Compressed, contains mask
344    M4,
345    /// Compressed, contains mask
346    M5,
347    /// Reserved for future compression algorithm
348    M6,
349    /// Resrved for future complex SAR compression
350    M7,
351    /// ISO JPEG 2000
352    M8,
353}
354
355/// Image data storage mode
356#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
357pub enum Mode {
358    #[default]
359    /// Band interleaved by block
360    B,
361    /// Band interleaved by pixel
362    P,
363    /// Band interleaved by row
364    R,
365    /// Band sequential
366    S,
367}
368
369// FUNCTIONS
370/// Helper function for parsing bands
371fn read_bands(reader: &mut (impl Read + Seek), n_band: u32) -> NitfResult<Vec<Band>> {
372    let mut bands: Vec<Band> = vec![Band::default(); n_band as usize];
373    for band in &mut bands {
374        band.irepband.read(reader)?;
375        band.isubcat.read(reader)?;
376        band.ifc.read(reader)?;
377        band.imflt.read(reader)?;
378        band.nluts.read(reader)?;
379        if band.nluts.val != 0 {
380            band.nelut.read(reader)?;
381            // Now we have a vector of the lut's.
382            band.lutd = vec![vec![0; band.nelut.val as usize]; band.nluts.val as usize];
383            for lut in band.lutd.iter_mut() {
384                // Here we have a vector which is a single LUT. Read into it.
385                // Crash if there is an error reading the bytes
386                reader
387                    .read_exact(lut)
388                    .or(Err(NitfError::ReadFatal("LUTD".to_string())))?;
389            }
390        }
391    }
392    Ok(bands)
393}
394/// Helper function for writing bands
395fn write_bands(writer: &mut (impl Write + Seek), bands: &Vec<Band>) -> NitfResult<usize> {
396    let mut bytes_written = 0;
397    for band in bands {
398        bytes_written += band.irepband.write(writer)?;
399        bytes_written += band.isubcat.write(writer)?;
400        bytes_written += band.ifc.write(writer)?;
401        bytes_written += band.imflt.write(writer)?;
402        bytes_written += band.nluts.write(writer)?;
403        if band.nluts.val != 0 {
404            band.nelut.write(writer)?;
405            for lut in band.lutd.iter() {
406                bytes_written += writer.write(lut).map_err(NitfError::IOError)?
407            }
408        }
409    }
410    Ok(bytes_written)
411}
412fn is_comrat(compression: &Compression) -> bool {
413    matches!(
414        compression,
415        Compression::C1
416            | Compression::C3
417            | Compression::C4
418            | Compression::C5
419            | Compression::C8
420            | Compression::M1
421            | Compression::M3
422            | Compression::M4
423            | Compression::M5
424            | Compression::M8
425            | Compression::I1
426    )
427}
428
429// TRAIT IMPLEMENTATIONS
430impl NitfSegmentHeader for ImageHeader {
431    fn read(&mut self, reader: &mut (impl Read + Seek)) -> NitfResult<()> {
432        self.im.read(reader)?;
433        self.iid1.read(reader)?;
434        self.idatim.read(reader)?;
435        self.tgtid.read(reader)?;
436        self.iid2.read(reader)?;
437        self.security.read(reader)?;
438        self.encryp.read(reader)?;
439        self.isorce.read(reader)?;
440        self.nrows.read(reader)?;
441        self.ncols.read(reader)?;
442        self.pvtype.read(reader)?;
443        self.irep.read(reader)?;
444        self.icat.read(reader)?;
445        self.abpp.read(reader)?;
446        self.pjust.read(reader)?;
447        self.icords.read(reader)?;
448        if self.icords.val != CoordinateRepresentation::DEFAULT {
449            self.igeolo.read(reader)?;
450        }
451        self.nicom.read(reader)?;
452        self.icoms = vec![NitfField::init(80u8, "ICOM"); self.nicom.val.into()];
453        self.icoms.iter_mut().try_for_each(|com| com.read(reader))?;
454
455        self.ic.read(reader)?;
456        if is_comrat(&self.ic.val) {
457            self.comrat.read(reader)?;
458        }
459        self.nbands.read(reader)?;
460        // If NBANDS = 0, use XBANDS
461        if self.nbands.val != 0 {
462            self.bands = read_bands(reader, self.nbands.val as u32)?;
463        } else {
464            self.xbands.read(reader)?;
465            self.bands = read_bands(reader, self.xbands.val)?;
466        }
467        self.isync.read(reader)?;
468        self.imode.read(reader)?;
469        self.nbpr.read(reader)?;
470        self.nbpc.read(reader)?;
471        self.nppbh.read(reader)?;
472        self.nppbv.read(reader)?;
473        self.nbpp.read(reader)?;
474        self.idlvl.read(reader)?;
475        self.ialvl.read(reader)?;
476        self.iloc.read(reader)?;
477        self.imag.read(reader)?;
478        self.udidl.read(reader)?;
479        if self.udidl.val != 0 {
480            self.udofl.read(reader)?;
481            self.udid.read(reader, (self.udidl.val - 3) as usize)?;
482        }
483        self.ixshdl.read(reader)?;
484        if self.ixshdl.val != 0 {
485            self.ixsofl.read(reader)?;
486            self.ixshd.read(reader, (self.ixshdl.val - 3) as usize)?;
487        }
488        Ok(())
489    }
490    fn write(&self, writer: &mut (impl Write + Seek)) -> NitfResult<usize> {
491        let mut bytes_written = 0;
492        bytes_written += self.im.write(writer)?;
493        bytes_written += self.iid1.write(writer)?;
494        bytes_written += self.idatim.write(writer)?;
495        bytes_written += self.tgtid.write(writer)?;
496        bytes_written += self.iid2.write(writer)?;
497        bytes_written += self.security.write(writer)?;
498        bytes_written += self.encryp.write(writer)?;
499        bytes_written += self.isorce.write(writer)?;
500        bytes_written += self.nrows.write(writer)?;
501        bytes_written += self.ncols.write(writer)?;
502        bytes_written += self.pvtype.write(writer)?;
503        bytes_written += self.irep.write(writer)?;
504        bytes_written += self.icat.write(writer)?;
505        bytes_written += self.abpp.write(writer)?;
506        bytes_written += self.pjust.write(writer)?;
507        bytes_written += self.icords.write(writer)?;
508        if self.icords.val != CoordinateRepresentation::DEFAULT {
509            bytes_written += self.igeolo.write(writer)?;
510        }
511        self.nicom.write(writer)?;
512        for comment in &self.icoms {
513            bytes_written += comment.write(writer)?;
514        }
515
516        bytes_written += self.ic.write(writer)?;
517        if is_comrat(&self.ic.val) {
518            bytes_written += self.comrat.write(writer)?;
519        }
520        bytes_written += self.nbands.write(writer)?;
521        // If NBANDS = 0, use XBANDS
522        if self.nbands.val == 0 {
523            bytes_written += self.xbands.write(writer)?;
524        }
525        bytes_written += write_bands(writer, &self.bands)?;
526        bytes_written += self.isync.write(writer)?;
527        bytes_written += self.imode.write(writer)?;
528        bytes_written += self.nbpr.write(writer)?;
529        bytes_written += self.nbpc.write(writer)?;
530        bytes_written += self.nppbh.write(writer)?;
531        bytes_written += self.nppbv.write(writer)?;
532        bytes_written += self.nbpp.write(writer)?;
533        bytes_written += self.idlvl.write(writer)?;
534        bytes_written += self.ialvl.write(writer)?;
535        bytes_written += self.iloc.write(writer)?;
536        bytes_written += self.imag.write(writer)?;
537        bytes_written += self.udidl.write(writer)?;
538        if self.udidl.val != 0 {
539            bytes_written += self.udofl.write(writer)?;
540            bytes_written += self.udid.write(writer)?;
541        }
542        bytes_written += self.ixshdl.write(writer)?;
543        if self.ixshdl.val != 0 {
544            bytes_written += self.ixsofl.write(writer)?;
545            bytes_written += self.ixshd.write(writer)?;
546        }
547        Ok(bytes_written)
548    }
549    fn length(&self) -> usize {
550        let mut length = 0;
551        length += self.im.length;
552        length += self.iid1.length;
553        length += self.idatim.length;
554        length += self.tgtid.length;
555        length += self.iid2.length;
556        length += self.security.length();
557        length += self.encryp.length;
558        length += self.isorce.length;
559        length += self.nrows.length;
560        length += self.ncols.length;
561        length += self.pvtype.length;
562        length += self.irep.length;
563        length += self.icat.length;
564        length += self.abpp.length;
565        length += self.pjust.length;
566        length += self.icords.length;
567        if self.icords.val != CoordinateRepresentation::DEFAULT {
568            length += self.igeolo.length;
569        }
570        length += self.nicom.length;
571        for comment in &self.icoms {
572            length += comment.length;
573        }
574
575        length += self.ic.length;
576        if is_comrat(&self.ic.val) {
577            length += self.comrat.length;
578        }
579        length += self.nbands.length;
580        // If NBANDS = 0, use XBANDS
581        if self.nbands.val == 0 {
582            length += self.xbands.length;
583        }
584        length += &self.bands.iter().map(|b| b.length()).sum();
585        length += self.isync.length;
586        length += self.imode.length;
587        length += self.nbpr.length;
588        length += self.nbpc.length;
589        length += self.nppbh.length;
590        length += self.nppbv.length;
591        length += self.nbpp.length;
592        length += self.idlvl.length;
593        length += self.ialvl.length;
594        length += self.iloc.length;
595        length += self.imag.length;
596        length += self.udidl.length;
597        length += self.udidl.val as usize;
598        length += self.ixshdl.length;
599        length += self.ixshdl.val as usize;
600        length
601    }
602}
603impl Display for ImageHeader {
604    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
605        let mut out_str = String::default();
606        out_str += format!("{}, ", self.im).as_ref();
607        out_str += format!("{}, ", self.iid1).as_ref();
608        out_str += format!("{}, ", self.idatim).as_ref();
609        out_str += format!("{}, ", self.tgtid).as_ref();
610        out_str += format!("{}, ", self.iid2).as_ref();
611        out_str += format!("SECURITY: [{}], ", self.security).as_ref();
612        out_str += format!("{}, ", self.encryp).as_ref();
613        out_str += format!("{}, ", self.isorce).as_ref();
614        out_str += format!("{}, ", self.nrows).as_ref();
615        out_str += format!("{}, ", self.ncols).as_ref();
616        out_str += format!("{}, ", self.pvtype).as_ref();
617        out_str += format!("{}, ", self.irep).as_ref();
618        out_str += format!("{}, ", self.icat).as_ref();
619        out_str += format!("{}, ", self.abpp).as_ref();
620        out_str += format!("{}, ", self.pjust).as_ref();
621        out_str += format!("{}, ", self.icords).as_ref();
622        if self.icords.val != CoordinateRepresentation::DEFAULT {
623            out_str += format!("{}, ", self.igeolo).as_ref();
624        }
625        out_str += format!("{}, ", self.nicom).as_ref();
626        for (i_com, com) in self.icoms.iter().enumerate() {
627            out_str += format!("ICOM {i_com}: {com},",).as_ref();
628        }
629        out_str += format!("{}, ", self.ic).as_ref();
630        if is_comrat(&self.ic.val) {
631            out_str += format!("{}, ", self.comrat).as_ref();
632        }
633        out_str += format!("{}, ", self.nbands).as_ref();
634        for (i_band, band) in self.bands.iter().enumerate() {
635            out_str += format!("BAND {i_band}: [{band}], ").as_ref();
636        }
637        out_str += format!("{}, ", self.isync).as_ref();
638        out_str += format!("{}, ", self.imode).as_ref();
639        out_str += format!("{}, ", self.nbpr).as_ref();
640        out_str += format!("{}, ", self.nbpc).as_ref();
641        out_str += format!("{}, ", self.nppbh).as_ref();
642        out_str += format!("{}, ", self.nppbv).as_ref();
643        out_str += format!("{}, ", self.nbpp).as_ref();
644        out_str += format!("{}, ", self.idlvl).as_ref();
645        out_str += format!("{}, ", self.ialvl).as_ref();
646        out_str += format!("{}, ", self.iloc).as_ref();
647        out_str += format!("{}, ", self.imag).as_ref();
648        out_str += format!("{}, ", self.udidl).as_ref();
649        if self.udidl.val != 0 {
650            out_str += format!("{}, ", self.udofl).as_ref();
651            out_str += format!("{}, ", self.udid).as_ref();
652        }
653        out_str += format!("{}, ", self.ixshdl).as_ref();
654        if self.ixshdl.val != 0 {
655            out_str += format!("{}, ", self.ixsofl).as_ref();
656            out_str += format!("{}", self.ixshd).as_ref();
657        }
658        write!(f, "Image Header: {out_str}")
659    }
660}
661impl Display for Band {
662    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
663        let mut out_str = String::default();
664        out_str += format!("{}, ", self.irepband).as_ref();
665        out_str += format!("{}, ", self.isubcat).as_ref();
666        out_str += format!("{}, ", self.ifc).as_ref();
667        out_str += format!("{}, ", self.imflt).as_ref();
668        out_str += format!("{}, ", self.nluts).as_ref();
669        if self.nluts.val != 0 {
670            out_str += format!("{}, ", self.nelut).as_ref();
671            for (i_lut, lut) in self.lutd.iter().enumerate() {
672                for (i_elem, elem) in lut.iter().enumerate() {
673                    out_str += format!("LUT{i_lut}{i_elem}: {elem:<3X}, ").as_ref();
674                }
675            }
676        }
677        write!(f, "{out_str}")
678    }
679}
680impl FromStr for PixelValueType {
681    type Err = NitfError;
682    fn from_str(s: &str) -> Result<Self, Self::Err> {
683        match s {
684            "INT" => Ok(Self::INT),
685            "B" => Ok(Self::B),
686            "SI" => Ok(Self::SI),
687            "R" => Ok(Self::R),
688            "C" => Ok(Self::C),
689            _ => Err(NitfError::ParseError("PixelValueType".to_string())),
690        }
691    }
692}
693impl Display for PixelValueType {
694    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
695        match self {
696            Self::INT => write!(f, "INT"),
697            Self::B => write!(f, "B"),
698            Self::SI => write!(f, "SI"),
699            Self::R => write!(f, "R"),
700            Self::C => write!(f, "C"),
701        }
702    }
703}
704impl FromStr for ImageRepresentation {
705    type Err = NitfError;
706    fn from_str(s: &str) -> Result<Self, Self::Err> {
707        match s {
708            "MONO" => Ok(Self::MONO),
709            "RGB" => Ok(Self::RGB),
710            "RGB/LUT" => Ok(Self::RGBLUT),
711            "MULTI" => Ok(Self::MULTI),
712            "NODISPLY" => Ok(Self::NODISPLY),
713            "" => Ok(Self::NVECTOR),
714            "POLAR" => Ok(Self::POLAR),
715            "VPH" => Ok(Self::VPH),
716            "YCbCr601" => Ok(Self::YCbCr601),
717            _ => Err(NitfError::ParseError("ImageRepresentation".to_string())),
718        }
719    }
720}
721impl Display for ImageRepresentation {
722    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
723        match self {
724            Self::MONO => write!(f, "MONO"),
725            Self::RGB => write!(f, "RGB"),
726            Self::RGBLUT => write!(f, "RGB/LUT"),
727            Self::MULTI => write!(f, "MULTI"),
728            Self::NODISPLY => write!(f, "NODISPLY"),
729            Self::NVECTOR => write!(f, "NVECTOR"),
730            Self::POLAR => write!(f, "POLAR"),
731            Self::VPH => write!(f, "VPH"),
732            Self::YCbCr601 => write!(f, "YCbCr601"),
733        }
734    }
735}
736impl FromStr for ImageRepresentationBand {
737    type Err = NitfError;
738    fn from_str(s: &str) -> Result<Self, Self::Err> {
739        match s {
740            "" => Ok(Self::DEFAULT),
741            "M" => Ok(Self::M),
742            "R" => Ok(Self::R),
743            "G" => Ok(Self::G),
744            "B" => Ok(Self::B),
745            "LU" => Ok(Self::LU),
746            "Y" => Ok(Self::Y),
747            "Cb" => Ok(Self::Cb),
748            "Cr" => Ok(Self::Cr),
749            _ => Err(NitfError::ParseError("ImageRepresentationBand".to_string())),
750        }
751    }
752}
753impl Display for ImageRepresentationBand {
754    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
755        match self {
756            Self::DEFAULT => write!(f, ""),
757            Self::M => write!(f, "M"),
758            Self::R => write!(f, "R"),
759            Self::G => write!(f, "G"),
760            Self::B => write!(f, "B"),
761            Self::LU => write!(f, "LU"),
762            Self::Y => write!(f, "Y"),
763            Self::Cb => write!(f, "Cb"),
764            Self::Cr => write!(f, "Cr"),
765        }
766    }
767}
768impl FromStr for ImageFilterCondition {
769    type Err = NitfError;
770    fn from_str(s: &str) -> Result<Self, Self::Err> {
771        match s {
772            "N" => Ok(Self::N),
773            _ => Err(NitfError::ParseError("PixelJustification".to_string())),
774        }
775    }
776}
777impl Display for ImageFilterCondition {
778    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
779        match self {
780            Self::N => write!(f, "N"),
781        }
782    }
783}
784impl FromStr for PixelJustification {
785    type Err = NitfError;
786    fn from_str(s: &str) -> Result<Self, Self::Err> {
787        match s {
788            "R" => Ok(Self::R),
789            "L" => Ok(Self::L),
790            _ => Err(NitfError::ParseError("PixelJustification".to_string())),
791        }
792    }
793}
794impl Display for PixelJustification {
795    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
796        match self {
797            Self::R => write!(f, "R"),
798            Self::L => write!(f, "L"),
799        }
800    }
801}
802impl FromStr for CoordinateRepresentation {
803    type Err = NitfError;
804    fn from_str(s: &str) -> Result<Self, Self::Err> {
805        match s {
806            "" => Ok(Self::DEFAULT),
807            "U" => Ok(Self::U),
808            "N" => Ok(Self::N),
809            "S" => Ok(Self::S),
810            "P" => Ok(Self::P),
811            "G" => Ok(Self::G),
812            "D" => Ok(Self::D),
813            _ => Err(NitfError::ParseError(
814                "CoordinateRepresentation".to_string(),
815            )),
816        }
817    }
818}
819impl Display for CoordinateRepresentation {
820    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
821        match self {
822            Self::DEFAULT => write!(f, ""),
823            Self::U => write!(f, "U"),
824            Self::N => write!(f, "N"),
825            Self::S => write!(f, "S"),
826            Self::P => write!(f, "P"),
827            Self::G => write!(f, "G"),
828            Self::D => write!(f, "D"),
829        }
830    }
831}
832impl FromStr for Compression {
833    type Err = NitfError;
834    fn from_str(s: &str) -> Result<Self, Self::Err> {
835        match s {
836            "NC" => Ok(Self::NC),
837            "NM" => Ok(Self::NM),
838            "C1" => Ok(Self::C1),
839            "C3" => Ok(Self::C3),
840            "C4" => Ok(Self::C4),
841            "C5" => Ok(Self::C5),
842            "C6" => Ok(Self::C6),
843            "C7" => Ok(Self::C7),
844            "C8" => Ok(Self::C8),
845            "I1" => Ok(Self::I1),
846            "M1" => Ok(Self::M1),
847            "M3" => Ok(Self::M3),
848            "M4" => Ok(Self::M4),
849            "M5" => Ok(Self::M5),
850            "M6" => Ok(Self::M6),
851            "M7" => Ok(Self::M7),
852            "M8" => Ok(Self::M8),
853            _ => Err(NitfError::ParseError("Compression".to_string())),
854        }
855    }
856}
857impl Display for Compression {
858    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
859        match self {
860            Self::NC => write!(f, "NC"),
861            Self::NM => write!(f, "NM"),
862            Self::C1 => write!(f, "C1"),
863            Self::C3 => write!(f, "C3"),
864            Self::C4 => write!(f, "C4"),
865            Self::C5 => write!(f, "C5"),
866            Self::C6 => write!(f, "C6"),
867            Self::C7 => write!(f, "C7"),
868            Self::C8 => write!(f, "C8"),
869            Self::I1 => write!(f, "I1"),
870            Self::M1 => write!(f, "M1"),
871            Self::M3 => write!(f, "M3"),
872            Self::M4 => write!(f, "M4"),
873            Self::M5 => write!(f, "M5"),
874            Self::M6 => write!(f, "M6"),
875            Self::M7 => write!(f, "M7"),
876            Self::M8 => write!(f, "M8"),
877        }
878    }
879}
880impl FromStr for Mode {
881    type Err = NitfError;
882    fn from_str(s: &str) -> Result<Self, Self::Err> {
883        match s {
884            "B" => Ok(Self::B),
885            "P" => Ok(Self::P),
886            "R" => Ok(Self::R),
887            "S" => Ok(Self::S),
888            _ => Err(NitfError::ParseError("Mode".to_string())),
889        }
890    }
891}
892impl Display for Mode {
893    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
894        match self {
895            Self::B => write!(f, "B"),
896            Self::P => write!(f, "P"),
897            Self::R => write!(f, "R"),
898            Self::S => write!(f, "S"),
899        }
900    }
901}