devela/media/image/sixel/output/
mod.rs

1// devela::media::image::sixel::output
2//
3//! Defines private [`SixelNode`], [`SixelOutput`].
4//
5// TOC
6// - SixelNode
7// - SixelOutput
8// - impl SixelOutput
9//
10// TODO: NEED:
11
12use crate::{IoWrite, String, Vec};
13
14mod enums; // RETHINK relocate
15mod pixel_format; // PixelFormat
16mod tosixel;
17pub use enums::*;
18pub use pixel_format::*;
19
20/// Represents a single sixel tile with color and spatial properties.
21///
22/// Holds the palette index, x-coordinates, and a map of color data
23/// for efficient rendering of individual sixel tiles.
24///
25/// # Adaptation
26/// - Derived from `sixel_node` struct in the `libsixel` C library.
27#[derive(Debug, Default, PartialEq, Eq, Hash)]
28pub(crate) struct SixelNode {
29    /// Index of the color in the palette.
30    pub pal: i32,
31    /// Start x-coordinate of the tile.
32    pub sx: i32,
33    /// End x-coordinate of the tile.
34    pub mx: i32,
35    /// Color data map for the tile.
36    pub map: Vec<u8>,
37}
38impl SixelNode {
39    pub fn new(pal: i32, sx: i32, mx: i32, map: Vec<u8>) -> Self {
40        Self { pal, sx, mx, map }
41    }
42}
43
44/// Handles sixel data output to a specified writer destination.
45///
46/// Abstracts over writing sixel-encoded data,
47/// supporting various output targets such as files or terminal streams.
48///
49/// # Adaptation
50/// - Derived from `sixel_output` struct in the `libsixel` C library.
51#[derive(Debug, Default, PartialEq, Eq, Hash)]
52pub(crate) struct SixelOutput<W: IoWrite> {
53    /* public fields
54     */
55    /// Palette selection mode.
56    pub color_model: SixelColorModel,
57
58    /// Writer for output, managing data destination.
59    pub fn_write: W,
60
61    /// Last saved pixel value.
62    pub save_pixel: u8,
63    /// Count of consecutive saved pixels.
64    pub save_count: i32,
65    /// Currently active palette index.
66    pub active_palette: i32,
67
68    /// Collection of sixel nodes for dithering.
69    pub nodes: Vec<SixelNode>,
70
71    /// Flag to allow penetration of the multiplexer.
72    pub penetrate_multiplexer: bool,
73    /// Policy for encoding decisions.
74    pub encode_policy: SixelEncodePolicy,
75
76    /// Buffer for output data.
77    pub buffer: String,
78
79    /* private compatibility flags
80     */
81    /// Indicates 8-bit terminal support.
82    ///
83    /// `false` for 7-bit, `true` for 8-bit.
84    pub(crate) has_8bit_control: bool,
85
86    /// Sixel scrolling support flag.
87    ///
88    /// `false` if terminal supports scrolling, `true` if not.
89    pub(crate) has_sixel_scrolling: bool,
90
91    /// Argument limit for repeat introducer (DECGRI).
92    ///
93    /// `false` if limited to 255, `true` if unlimited.
94    pub(crate) has_gri_arg_limit: bool,
95
96    /// DECSDM (CSI ? 80 h) sixel scrolling glitch flag.
97    ///
98    /// `false` enables sixel scrolling, `true` disables it.
99    pub(crate) has_sdm_glitch: bool,
100
101    /// Flag to skip DCS envelope handling.
102    ///
103    /// `false` to process, `true` to skip.
104    pub(crate) skip_dcs_envelope: bool,
105}
106
107// general methods annd constants
108#[allow(dead_code, reason = "crate private struct")]
109impl<W: IoWrite> SixelOutput<W> {
110    /// Device Control String start and end sequences
111    pub(crate) const DCS_START_7BIT: &str = "\x1BP";
112    pub(crate) const DCS_START_8BIT: &str = "\u{220}";
113    pub(crate) const DCS_END_7BIT: &str = "\x1B\\";
114    pub(crate) const DCS_END_8BIT: &str = "\u{234}";
115
116    /// Used in `penetrate`.
117    pub(crate) const SCREEN_PACKET_SIZE: usize = 256;
118
119    /// Packet size limit.
120    /// Used in `advance`.
121    pub(crate) const PACKET_SIZE: usize = 16_384;
122
123    /// Used in `encode_high_color`.
124    pub(crate) const PALETTE_HIT: i32 = 1;
125    pub(crate) const PALETTE_CHANGE: i32 = 2;
126
127    /// Create new output context object
128    pub fn new(fn_write: W) -> Self {
129        Self {
130            has_8bit_control: false,
131            has_sdm_glitch: false,
132            has_gri_arg_limit: true,
133            skip_dcs_envelope: false,
134            color_model: SixelColorModel::Auto,
135            fn_write,
136            save_pixel: 0,
137            save_count: 0,
138            active_palette: -1,
139            nodes: Vec::new(),
140            penetrate_multiplexer: false,
141            encode_policy: SixelEncodePolicy::Auto,
142            has_sixel_scrolling: false,
143            buffer: String::new(),
144        }
145    }
146
147    /// Get 8bit output mode which indicates whether it uses C1 control characters.
148    #[must_use]
149    pub fn get_8bit_availability(&self) -> bool {
150        self.has_8bit_control
151    }
152    /// Set 8bit output mode state.
153    pub fn set_8bit_availability(&mut self, availability: bool) {
154        self.has_8bit_control = availability;
155    }
156
157    /// Set limit for repeat introducer (DECGRI).
158    ///
159    /// `false` if limited to 255, `true` if unlimited.
160    pub fn set_gri_arg_limit(&mut self, value: bool) {
161        self.has_gri_arg_limit = value;
162    }
163
164    /// Set GNU Screen penetration.
165    pub fn set_penetrate_multiplexer(&mut self, penetrate: bool) {
166        self.penetrate_multiplexer = penetrate;
167    }
168
169    /// Set whether we skip DCS envelope.
170    pub fn set_skip_dcs_envelope(&mut self, skip: bool) {
171        self.skip_dcs_envelope = skip;
172    }
173
174    /// Set the color model.
175    pub fn set_color_model(&mut self, color_model: SixelColorModel) {
176        self.color_model = color_model;
177    }
178
179    /// Set the encoding policy.
180    pub fn set_encode_policy(&mut self, encode_policy: SixelEncodePolicy) {
181        self.encode_policy = encode_policy;
182    }
183}