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 skip_trailing_padding(buf);
83
84 Ok(Tx3g {
85 data_reference_index,
86 display_flags,
87 horizontal_justification,
88 vertical_justification,
89 bg_color_rgba,
90 box_record,
91 style_record,
92 ftab,
93 })
94 }
95
96 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
97 0u32.encode(buf)?; 0u16.encode(buf)?; self.data_reference_index.encode(buf)?;
100 self.display_flags.encode(buf)?;
101 self.horizontal_justification.encode(buf)?;
102 self.vertical_justification.encode(buf)?;
103 self.bg_color_rgba.red.encode(buf)?;
104 self.bg_color_rgba.green.encode(buf)?;
105 self.bg_color_rgba.blue.encode(buf)?;
106 self.bg_color_rgba.alpha.encode(buf)?;
107 for n in 0..4 {
108 (self.box_record[n]).encode(buf)?;
109 }
110 for n in 0..12 {
111 (self.style_record[n]).encode(buf)?;
112 }
113 self.ftab.encode(buf)?;
114
115 Ok(())
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn test_tx3g() {
125 let expected = Tx3g {
126 data_reference_index: 1,
127 display_flags: 0,
128 horizontal_justification: 1,
129 vertical_justification: -1,
130 bg_color_rgba: RgbaColor {
131 red: 0,
132 green: 0,
133 blue: 0,
134 alpha: 255,
135 },
136 box_record: [0, 0, 0, 0],
137 style_record: [0, 0, 0, 0, 0, 1, 0, 16, 255, 255, 255, 255],
138 ftab: None,
139 };
140 let mut buf = Vec::new();
141 expected.encode(&mut buf).unwrap();
142
143 let mut buf = buf.as_ref();
144 let decoded = Tx3g::decode(&mut buf).unwrap();
145 assert_eq!(decoded, expected);
146 }
147
148 const ENCODED_TX3G_09: &[u8] = &[
150 0x00, 0x00, 0x00, 0x40, 0x74, 0x78, 0x33, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
151 0x01, 0x00, 0x04, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
152 0x00, 0x3c, 0x01, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x12, 0xff, 0xff, 0xff,
153 0xff, 0x00, 0x00, 0x00, 0x12, 0x66, 0x74, 0x61, 0x62, 0x00, 0x01, 0x00, 0x01, 0x05, 0x53,
154 0x65, 0x72, 0x69, 0x66,
155 ];
156
157 fn get_reference_mpeg_09_tx3g() -> Tx3g {
209 Tx3g {
210 data_reference_index: 1,
211 display_flags: 0x00040000,
212 horizontal_justification: 1,
213 vertical_justification: -1,
214 bg_color_rgba: RgbaColor {
215 red: 0xFF,
216 green: 0x00,
217 blue: 0x00,
218 alpha: 0xFF,
219 },
220 box_record: [0, 0, 60, 400],
221 style_record: [0, 0, 0, 0, 0, 1, 0, 18, 255, 255, 255, 255],
222 ftab: Some(Ftab {
223 font_entries: vec![FontEntry {
224 font_id: 1,
225 font: "Serif".into(),
226 }],
227 }),
228 }
229 }
230 #[test]
231 fn test_mpeg_09_text_decode() {
232 let buf: &mut std::io::Cursor<&&[u8]> = &mut std::io::Cursor::new(&ENCODED_TX3G_09);
233 let tx3g = Tx3g::decode(buf).expect("failed to decode tx3g");
234 assert_eq!(tx3g, get_reference_mpeg_09_tx3g());
235 }
236
237 #[test]
238 fn test_mpeg_09_text_encode() {
239 let tx3g = get_reference_mpeg_09_tx3g();
240 let mut buf = Vec::new();
241 tx3g.encode(&mut buf).unwrap();
242 assert_eq!(buf.as_slice(), ENCODED_TX3G_09);
243 }
244}