1use crate::*;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub struct Tx3g {
10 pub data_reference_index: u16,
11 pub display_flags: u32,
12 pub horizontal_justification: i8,
13 pub vertical_justification: i8,
14 pub bg_color_rgba: RgbaColor,
15 pub box_record: [i16; 4],
16 pub style_record: [u8; 12],
17 pub ftab: Option<Ftab>,
19 }
21
22#[derive(Debug, Clone, PartialEq, Eq, Default)]
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24pub struct RgbaColor {
25 pub red: u8,
26 pub green: u8,
27 pub blue: u8,
28 pub alpha: u8,
29}
30
31impl Default for Tx3g {
32 fn default() -> Self {
33 Tx3g {
34 data_reference_index: 0,
35 display_flags: 0,
36 horizontal_justification: 1,
37 vertical_justification: -1,
38 bg_color_rgba: RgbaColor {
39 red: 0,
40 green: 0,
41 blue: 0,
42 alpha: 255,
43 },
44 box_record: [0, 0, 0, 0],
45 style_record: [0, 0, 0, 0, 0, 1, 0, 16, 255, 255, 255, 255],
46 ftab: None, }
48 }
49}
50
51impl Atom for Tx3g {
52 const KIND: FourCC = FourCC::new(b"tx3g");
53
54 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
55 u32::decode(buf)?; u16::decode(buf)?; let data_reference_index = u16::decode(buf)?;
58
59 let display_flags = u32::decode(buf)?;
60 let horizontal_justification = i8::decode(buf)?;
61 let vertical_justification = i8::decode(buf)?;
62 let bg_color_rgba = RgbaColor {
63 red: u8::decode(buf)?,
64 green: u8::decode(buf)?,
65 blue: u8::decode(buf)?,
66 alpha: u8::decode(buf)?,
67 };
68 let box_record: [i16; 4] = [
69 i16::decode(buf)?,
70 i16::decode(buf)?,
71 i16::decode(buf)?,
72 i16::decode(buf)?,
73 ];
74 let style_record = <[u8; 12]>::decode(buf)?;
75 let mut ftab = None; while let Some(atom) = Any::decode_maybe(buf)? {
77 match atom {
78 Any::Ftab(atom) => ftab = atom.into(),
79 unknown => Self::decode_unknown(&unknown)?,
80 }
81 }
82
83 Ok(Tx3g {
84 data_reference_index,
85 display_flags,
86 horizontal_justification,
87 vertical_justification,
88 bg_color_rgba,
89 box_record,
90 style_record,
91 ftab,
92 })
93 }
94
95 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
96 0u32.encode(buf)?; 0u16.encode(buf)?; self.data_reference_index.encode(buf)?;
99 self.display_flags.encode(buf)?;
100 self.horizontal_justification.encode(buf)?;
101 self.vertical_justification.encode(buf)?;
102 self.bg_color_rgba.red.encode(buf)?;
103 self.bg_color_rgba.green.encode(buf)?;
104 self.bg_color_rgba.blue.encode(buf)?;
105 self.bg_color_rgba.alpha.encode(buf)?;
106 for n in 0..4 {
107 (self.box_record[n]).encode(buf)?;
108 }
109 for n in 0..12 {
110 (self.style_record[n]).encode(buf)?;
111 }
112 self.ftab.encode(buf)?;
113
114 Ok(())
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn test_tx3g() {
124 let expected = Tx3g {
125 data_reference_index: 1,
126 display_flags: 0,
127 horizontal_justification: 1,
128 vertical_justification: -1,
129 bg_color_rgba: RgbaColor {
130 red: 0,
131 green: 0,
132 blue: 0,
133 alpha: 255,
134 },
135 box_record: [0, 0, 0, 0],
136 style_record: [0, 0, 0, 0, 0, 1, 0, 16, 255, 255, 255, 255],
137 ftab: None,
138 };
139 let mut buf = Vec::new();
140 expected.encode(&mut buf).unwrap();
141
142 let mut buf = buf.as_ref();
143 let decoded = Tx3g::decode(&mut buf).unwrap();
144 assert_eq!(decoded, expected);
145 }
146
147 const ENCODED_TX3G_09: &[u8] = &[
149 0x00, 0x00, 0x00, 0x40, 0x74, 0x78, 0x33, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150 0x01, 0x00, 0x04, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
151 0x00, 0x3c, 0x01, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x12, 0xff, 0xff, 0xff,
152 0xff, 0x00, 0x00, 0x00, 0x12, 0x66, 0x74, 0x61, 0x62, 0x00, 0x01, 0x00, 0x01, 0x05, 0x53,
153 0x65, 0x72, 0x69, 0x66,
154 ];
155
156 fn get_reference_mpeg_09_tx3g() -> Tx3g {
208 Tx3g {
209 data_reference_index: 1,
210 display_flags: 0x00040000,
211 horizontal_justification: 1,
212 vertical_justification: -1,
213 bg_color_rgba: RgbaColor {
214 red: 0xFF,
215 green: 0x00,
216 blue: 0x00,
217 alpha: 0xFF,
218 },
219 box_record: [0, 0, 60, 400],
220 style_record: [0, 0, 0, 0, 0, 1, 0, 18, 255, 255, 255, 255],
221 ftab: Some(Ftab {
222 font_entries: vec![FontEntry {
223 font_id: 1,
224 font: "Serif".into(),
225 }],
226 }),
227 }
228 }
229 #[test]
230 fn test_mpeg_09_text_decode() {
231 let buf: &mut std::io::Cursor<&&[u8]> = &mut std::io::Cursor::new(&ENCODED_TX3G_09);
232 let tx3g = Tx3g::decode(buf).expect("failed to decode tx3g");
233 assert_eq!(tx3g, get_reference_mpeg_09_tx3g());
234 }
235
236 #[test]
237 fn test_mpeg_09_text_encode() {
238 let tx3g = get_reference_mpeg_09_tx3g();
239 let mut buf = Vec::new();
240 tx3g.encode(&mut buf).unwrap();
241 assert_eq!(buf.as_slice(), ENCODED_TX3G_09);
242 }
243}