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(
14 feature = "tracing",
15 tracing::instrument(level = "debug", skip(writer, tga))
16)]
17pub fn write_tga<W: Write>(writer: &mut W, tga: &Tga) -> Result<(), TgaBinaryError> {
18 validate_rgba_len(tga.header.width, tga.header.height, &tga.rgba_pixels)?;
19 write_tga_canonical(writer, tga)
20}
21
22#[cfg_attr(feature = "tracing", tracing::instrument(level = "debug", skip(tga)))]
24pub fn write_tga_to_vec(tga: &Tga) -> Result<Vec<u8>, TgaBinaryError> {
25 let mut cursor = Cursor::new(Vec::new());
26 write_tga(&mut cursor, tga)?;
27 Ok(cursor.into_inner())
28}
29
30fn write_tga_canonical<W: Write>(writer: &mut W, tga: &Tga) -> Result<(), TgaBinaryError> {
31 let id_len = u8::try_from(tga.image_id.len())
32 .map_err(|_| TgaBinaryError::InvalidHeader("image_id is longer than 255 bytes".into()))?;
33
34 write_u8(writer, id_len)?;
35 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)?;
45 write_u16(writer, tga.header.height)?;
46 write_u8(writer, 32)?; write_u8(writer, 0x20 | 0x08)?; writer.write_all(&tga.image_id)?;
49 write_truecolor_uncompressed(writer, &tga.rgba_pixels, true)?;
50 Ok(())
51}
52
53fn write_truecolor_uncompressed<W: Write>(
54 writer: &mut W,
55 rgba_pixels: &[u8],
56 include_alpha: bool,
57) -> Result<(), TgaBinaryError> {
58 for rgba in rgba_pixels.chunks_exact(4) {
59 if include_alpha {
60 writer.write_all(&[rgba[2], rgba[1], rgba[0], rgba[3]])?;
61 } else {
62 writer.write_all(&[rgba[2], rgba[1], rgba[0]])?;
63 }
64 }
65 Ok(())
66}