rakata_formats/tga/
writer.rs1use std::io::{Cursor, Write};
4
5use crate::binary::{write_u16, write_u8};
6
7use super::{validate_rgba_len, Tga, TgaBinaryError};
8
9#[cfg_attr(
24 feature = "tracing",
25 tracing::instrument(level = "debug", skip(writer, tga))
26)]
27pub fn write_tga<W: Write>(writer: &mut W, tga: &Tga) -> Result<(), TgaBinaryError> {
28 validate_rgba_len(tga.header.width, tga.header.height, &tga.rgba_pixels)?;
29 write_tga_canonical(writer, tga)
30}
31
32#[cfg_attr(feature = "tracing", tracing::instrument(level = "debug", skip(tga)))]
39pub fn write_tga_to_vec(tga: &Tga) -> Result<Vec<u8>, TgaBinaryError> {
40 let mut cursor = Cursor::new(Vec::new());
41 write_tga(&mut cursor, tga)?;
42 Ok(cursor.into_inner())
43}
44
45fn write_tga_canonical<W: Write>(writer: &mut W, tga: &Tga) -> Result<(), TgaBinaryError> {
46 let id_len = u8::try_from(tga.image_id.len())
47 .map_err(|_| TgaBinaryError::InvalidHeader("image_id is longer than 255 bytes".into()))?;
48
49 write_u8(writer, id_len)?;
50 write_u8(writer, 0)?; write_u8(writer, 2)?; write_u16(writer, 0)?; write_u16(writer, 0)?; write_u8(writer, 0)?; write_u16(writer, 0)?; write_u16(writer, 0)?; write_u16(writer, tga.header.width)?;
60 write_u16(writer, tga.header.height)?;
61 write_u8(writer, 32)?; write_u8(writer, 0x20 | 0x08)?; writer.write_all(&tga.image_id)?;
64 write_truecolor_uncompressed(writer, &tga.rgba_pixels, true)?;
65 Ok(())
66}
67
68fn write_truecolor_uncompressed<W: Write>(
69 writer: &mut W,
70 rgba_pixels: &[u8],
71 include_alpha: bool,
72) -> Result<(), TgaBinaryError> {
73 for rgba in rgba_pixels.chunks_exact(4) {
74 if include_alpha {
75 writer.write_all(&[rgba[2], rgba[1], rgba[0], rgba[3]])?;
76 } else {
77 writer.write_all(&[rgba[2], rgba[1], rgba[0]])?;
78 }
79 }
80 Ok(())
81}