nitf_rs/headers/
graphic_hdr.rs

1//! Graphic segment subheader definition
2use std::fmt::Display;
3use std::io::{Read, Seek, Write};
4use std::str::FromStr;
5
6use crate::headers::NitfSegmentHeader;
7use crate::types::{ExtendedSubheader, NitfField, Security};
8use crate::{NitfError, NitfResult};
9/// Header fields for Graphic Segment
10#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
11pub struct GraphicHeader {
12    /// File Part Type
13    pub sy: NitfField<SY>,
14    /// Graphic Identifier
15    pub sid: NitfField<String>,
16    /// Graphic Name
17    pub sname: NitfField<String>,
18    /// Security information
19    pub security: Security,
20    /// Encryption
21    pub encryp: NitfField<String>,
22    /// Graphic Type
23    pub sfmt: NitfField<Format>,
24    /// Reserved for Future Use
25    pub sstruct: NitfField<u64>,
26    /// Graphic Display Level
27    pub sdlvl: NitfField<u16>,
28    /// Graphic Attachment Level
29    pub salvl: NitfField<u16>,
30    /// Graphic Location
31    pub sloc: NitfField<BoundLocation>, // TODO: Same image image ILOC type thing
32    /// First Graphic Bound Location
33    pub sbnd1: NitfField<BoundLocation>,
34    /// Graphic Color
35    pub scolor: NitfField<Color>,
36    /// Second Graphic Bound Location
37    pub sbnd2: NitfField<BoundLocation>,
38    /// Reserved for Future Use
39    pub sres2: NitfField<u8>,
40    /// Graphic Extended Subheader Data Length
41    pub sxshdl: NitfField<u16>,
42    /// Graphic Extended Subheader Overflow
43    pub sxsofl: NitfField<u16>,
44    /// Graphic Extended Subheader Data
45    pub sxshd: ExtendedSubheader,
46}
47impl Default for GraphicHeader {
48    fn default() -> Self {
49        Self {
50            sy: NitfField::init(2u8, "SY"),
51            sid: NitfField::init(10u8, "SID"),
52            sname: NitfField::init(20u8, "SNAME"),
53            security: Security::default(),
54            encryp: NitfField::init(1u8, "ENCRYP"),
55            sfmt: NitfField::init(1u8, "SFMT"),
56            sstruct: NitfField::init(13u8, "SSTRUCT"),
57            sdlvl: NitfField::init(3u8, "SDLVL"),
58            salvl: NitfField::init(3u8, "SALVL"),
59            sloc: NitfField::init(10u8, "SLOC"),
60            sbnd1: NitfField::init(10u8, "SBND1"),
61            scolor: NitfField::init(1u8, "SCOLOR"),
62            sbnd2: NitfField::init(10u8, "SBND2"),
63            sres2: NitfField::init(2u8, "SRES2"),
64            sxshdl: NitfField::init(5u8, "SXSHDL"),
65            sxsofl: NitfField::init(3u8, "SXSOFL"),
66            sxshd: ExtendedSubheader::init("SXSHD"),
67        }
68    }
69}
70#[derive(Default, Clone, Debug, Eq, PartialEq, Copy, Ord, PartialOrd)]
71pub enum SY {
72    #[default]
73    SY,
74}
75impl FromStr for SY {
76    type Err = NitfError;
77    fn from_str(s: &str) -> Result<Self, Self::Err> {
78        match s {
79            "SY" => Ok(Self::default()),
80            _ => Err(NitfError::ParseError("SY".to_string())),
81        }
82    }
83}
84impl Display for SY {
85    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86        write!(f, "SY")
87    }
88}
89
90impl Display for GraphicHeader {
91    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92        let mut out_str = String::default();
93        out_str += format!("{}, ", self.sy).as_ref();
94        out_str += format!("{}, ", self.sid).as_ref();
95        out_str += format!("{}, ", self.sname).as_ref();
96        out_str += format!("SECURITY: [{}], ", self.security).as_ref();
97        out_str += format!("{}, ", self.encryp).as_ref();
98        out_str += format!("{}, ", self.sfmt).as_ref();
99        out_str += format!("{}, ", self.sstruct).as_ref();
100        out_str += format!("{}, ", self.sdlvl).as_ref();
101        out_str += format!("{}, ", self.salvl).as_ref();
102        out_str += format!("{}, ", self.sloc).as_ref();
103        out_str += format!("{}, ", self.sbnd1).as_ref();
104        out_str += format!("{}, ", self.scolor).as_ref();
105        out_str += format!("{}, ", self.sbnd2).as_ref();
106        out_str += format!("{}, ", self.sres2).as_ref();
107        out_str += format!("{}, ", self.sxshdl).as_ref();
108        out_str += format!("{}, ", self.sxsofl).as_ref();
109        out_str += format!("{}", self.sxshd).as_ref();
110        write!(f, "Graphic Header: [{out_str}]")
111    }
112}
113impl NitfSegmentHeader for GraphicHeader {
114    fn read(&mut self, reader: &mut (impl Read + Seek)) -> NitfResult<()> {
115        self.sy.read(reader)?;
116        self.sid.read(reader)?;
117        self.sname.read(reader)?;
118        self.security.read(reader)?;
119        self.encryp.read(reader)?;
120        self.sfmt.read(reader)?;
121        self.sstruct.read(reader)?;
122        self.sdlvl.read(reader)?;
123        self.salvl.read(reader)?;
124        self.sloc.read(reader)?;
125        self.sbnd1.read(reader)?;
126        self.scolor.read(reader)?;
127        self.sbnd2.read(reader)?;
128        self.sres2.read(reader)?;
129        self.sxshdl.read(reader)?;
130        if self.sxshdl.val != 0 {
131            self.sxsofl.read(reader)?;
132            self.sxshd.read(reader, (self.sxshdl.val - 3) as usize)?;
133        }
134        Ok(())
135    }
136    fn write(&self, writer: &mut (impl Write + Seek)) -> NitfResult<usize> {
137        let mut bytes_written = 0;
138        bytes_written += self.sy.write(writer)?;
139        bytes_written += self.sid.write(writer)?;
140        bytes_written += self.sname.write(writer)?;
141        bytes_written += self.security.write(writer)?;
142        bytes_written += self.encryp.write(writer)?;
143        bytes_written += self.sfmt.write(writer)?;
144        bytes_written += self.sstruct.write(writer)?;
145        bytes_written += self.sdlvl.write(writer)?;
146        bytes_written += self.salvl.write(writer)?;
147        bytes_written += self.sloc.write(writer)?;
148        bytes_written += self.sbnd1.write(writer)?;
149        bytes_written += self.scolor.write(writer)?;
150        bytes_written += self.sbnd2.write(writer)?;
151        bytes_written += self.sres2.write(writer)?;
152        bytes_written += self.sxshdl.write(writer)?;
153        if self.sxshdl.val != 0 {
154            bytes_written += self.sxsofl.write(writer)?;
155            bytes_written += self.sxshd.write(writer)?;
156        }
157        Ok(bytes_written)
158    }
159    fn length(&self) -> usize {
160        let mut length = 0;
161        length += self.sy.length;
162        length += self.sid.length;
163        length += self.sname.length;
164        length += self.security.length();
165        length += self.encryp.length;
166        length += self.sfmt.length;
167        length += self.sstruct.length;
168        length += self.sdlvl.length;
169        length += self.salvl.length;
170        length += self.sloc.length;
171        length += self.sbnd1.length;
172        length += self.scolor.length;
173        length += self.sbnd2.length;
174        length += self.sres2.length;
175        length += self.sxshdl.length;
176        if self.sxshdl.val != 0 {
177            length += self.sxsofl.length;
178            length += self.sxshd.size();
179        }
180        length
181    }
182}
183
184/// Graphic type. Right now standard only supports C
185#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
186pub enum Format {
187    #[default]
188    /// Computer graphics metafile
189    C,
190}
191
192impl FromStr for Format {
193    type Err = NitfError;
194    fn from_str(s: &str) -> Result<Self, Self::Err> {
195        match s {
196            "C" => Ok(Self::C),
197            _ => Err(NitfError::ParseError("Format".to_string())),
198        }
199    }
200}
201impl Display for Format {
202    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
203        match self {
204            Self::C => write!(f, "C"),
205        }
206    }
207}
208
209/// Graphic bound position relative to origin of coordinate system
210#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
211pub struct BoundLocation {
212    pub row: i32,
213    pub col: i32,
214}
215
216impl FromStr for BoundLocation {
217    type Err = NitfError;
218    fn from_str(s: &str) -> Result<Self, Self::Err> {
219        if s.len() == 10 {
220            let bounds = Self {
221                row: s[..5]
222                    .parse()
223                    .or(Err(NitfError::ParseError("BoundLocation.row".to_string())))?,
224                col: s[5..]
225                    .parse()
226                    .or(Err(NitfError::ParseError("BoundLocation.col".to_string())))?,
227            };
228            Ok(bounds)
229        } else {
230            Err(NitfError::ParseError("BoundLocation".to_string()))
231        }
232    }
233}
234impl Display for BoundLocation {
235    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236        write!(f, "{:0<5}{:0<5}", self.row, self.col)
237    }
238}
239/// Color type of graphics
240#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
241pub enum Color {
242    #[default]
243    /// Color pieces
244    C,
245    /// Monochrome
246    M,
247}
248
249impl FromStr for Color {
250    type Err = NitfError;
251    fn from_str(s: &str) -> Result<Self, Self::Err> {
252        match s {
253            "C" => Ok(Self::C),
254            "M" => Ok(Self::M),
255            _ => Err(NitfError::ParseError("Color".to_string())),
256        }
257    }
258}
259impl Display for Color {
260    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
261        match self {
262            Self::C => write!(f, "C"),
263            Self::M => write!(f, "M"),
264        }
265    }
266}