1use super::channel::ModularImage;
8use super::encode::{
9 build_histogram_from_residuals, collect_all_residuals, write_global_modular_section,
10 write_group_modular_section, write_improved_modular_stream, write_modular_stream_with_tree,
11};
12use super::section::write_global_modular_section_with_tree;
13use crate::GROUP_DIM;
14use crate::bit_writer::BitWriter;
15use crate::error::Result;
16use crate::headers::ColorEncoding;
17use crate::headers::frame_header::{BlendMode, FrameCrop, FrameHeader};
18
19#[derive(Debug, Clone)]
21pub struct FrameEncoderOptions {
22 pub use_modular: bool,
24 pub effort: u8,
26 pub use_ans: bool,
28 pub use_tree_learning: bool,
30 pub use_squeeze: bool,
32 pub have_animation: bool,
34 pub duration: u32,
36 pub is_last: bool,
38 pub crop: Option<FrameCrop>,
40}
41
42impl Default for FrameEncoderOptions {
43 fn default() -> Self {
44 Self {
45 use_modular: true, effort: 7,
47 use_ans: false,
48 use_tree_learning: false,
49 use_squeeze: false,
50 have_animation: false,
51 duration: 0,
52 is_last: true,
53 crop: None,
54 }
55 }
56}
57
58pub struct FrameEncoder {
60 #[allow(dead_code)]
62 options: FrameEncoderOptions,
63 width: usize,
65 height: usize,
67 #[allow(dead_code)]
68 num_extra_channels: usize,
70}
71
72impl FrameEncoder {
73 pub fn new(width: usize, height: usize, options: FrameEncoderOptions) -> Self {
75 Self {
76 options,
77 width,
78 height,
79 num_extra_channels: 0,
80 }
81 }
82
83 pub fn new_with_extra_channels(
85 width: usize,
86 height: usize,
87 options: FrameEncoderOptions,
88 num_extra_channels: usize,
89 ) -> Self {
90 Self {
91 options,
92 width,
93 height,
94 num_extra_channels,
95 }
96 }
97
98 pub fn encode_modular(
100 &self,
101 image: &ModularImage,
102 _color_encoding: &ColorEncoding,
103 writer: &mut BitWriter,
104 ) -> Result<()> {
105 let num_extra_channels = if image.has_alpha { 1 } else { 0 };
107
108 {
110 let mut fh = FrameHeader::lossless();
111 fh.ec_upsampling = vec![1; num_extra_channels];
112 fh.ec_blend_modes = vec![BlendMode::Replace; num_extra_channels];
113 fh.have_animation = self.options.have_animation;
114 fh.duration = self.options.duration;
115 fh.is_last = self.options.is_last;
116 if let Some(ref crop) = self.options.crop {
117 fh.x0 = crop.x0;
118 fh.y0 = crop.y0;
119 fh.width = crop.width;
120 fh.height = crop.height;
121 fh.blend_mode = BlendMode::Replace;
122 fh.blend_source = 1;
123 }
124 if self.options.have_animation && !self.options.is_last {
127 fh.save_as_reference = 1;
128 }
129 fh.write(writer)?;
130 }
131
132 let num_groups = self.num_groups();
133
134 if num_groups == 1 {
135 let mut section_writer = BitWriter::new();
137
138 if self.options.use_squeeze {
139 super::encode::write_modular_stream_with_squeeze(
140 image,
141 &mut section_writer,
142 self.options.use_ans,
143 )?;
144 } else if self.options.use_tree_learning && self.options.use_ans {
145 write_modular_stream_with_tree(
146 image,
147 &mut section_writer,
148 256, 1.0, image.channels.len() >= 3, )?;
152 } else {
153 write_improved_modular_stream(image, &mut section_writer, self.options.use_ans)?;
154 }
155
156 let section_data = section_writer.finish();
157 let section_size = section_data.len();
158
159 crate::trace::debug_eprintln!("FRAME_ENCODER: section_size = {} bytes", section_size);
160
161 self.write_toc(writer, section_size)?;
163
164 for byte in section_data {
166 writer.write_u8(byte)?;
167 }
168 } else {
169 self.encode_modular_multi_group(image, writer)?;
171 }
172
173 Ok(())
174 }
175
176 fn encode_modular_multi_group(
184 &self,
185 image: &ModularImage,
186 writer: &mut BitWriter,
187 ) -> Result<()> {
188 let num_groups = self.num_groups();
189 let num_lf_groups = self.num_lf_groups();
190 let num_passes = 1;
191
192 crate::trace::debug_eprintln!(
193 "MULTI_GROUP: Encoding {}x{} image with {} groups, {} lf_groups",
194 self.width,
195 self.height,
196 num_groups,
197 num_lf_groups
198 );
199
200 let mut group_images: Vec<ModularImage> = Vec::with_capacity(num_groups);
202 for group_idx in 0..num_groups {
203 let (x_start, y_start, x_end, y_end) = self.group_bounds(group_idx);
204 let group_image = image.extract_region(x_start, y_start, x_end, y_end)?;
205 group_images.push(group_image);
206 }
207
208 let mut lf_global_writer = BitWriter::new();
210 let global_state = if self.options.use_tree_learning && self.options.use_ans {
211 write_global_modular_section_with_tree(
213 &group_images,
214 &mut lf_global_writer,
215 256, 1.0, )?
218 } else {
219 let mut all_residuals = Vec::new();
221 let mut max_residual: u32 = 0;
222 for group_image in &group_images {
223 let (group_residuals, group_max) = collect_all_residuals(group_image);
224 all_residuals.extend(group_residuals);
225 max_residual = max_residual.max(group_max);
226 }
227 let (histogram, max_token) =
228 build_histogram_from_residuals(&all_residuals, max_residual);
229
230 crate::trace::debug_eprintln!(
231 "MULTI_GROUP: {} total residuals, max_raw={}, max_token={}, {} unique tokens",
232 all_residuals.len(),
233 max_residual,
234 max_token,
235 histogram.iter().filter(|&&c| c > 0).count()
236 );
237
238 write_global_modular_section(
239 &all_residuals,
240 &histogram,
241 max_token,
242 &mut lf_global_writer,
243 self.options.use_ans,
244 )?
245 };
246 let lf_global_data = lf_global_writer.finish();
247
248 crate::trace::debug_eprintln!(
249 "MULTI_GROUP: LfGlobal section = {} bytes",
250 lf_global_data.len()
251 );
252
253 let hf_global_data: Vec<u8> = Vec::new();
255 crate::trace::debug_eprintln!(
256 "MULTI_GROUP: HfGlobal section = 0 bytes (empty for modular)"
257 );
258
259 let lf_group_data: Vec<Vec<u8>> = (0..num_lf_groups).map(|_| Vec::new()).collect();
261 crate::trace::debug_eprintln!(
262 "MULTI_GROUP: {} LfGroup sections = 0 bytes each (empty for modular)",
263 num_lf_groups
264 );
265
266 let mut pass_group_data: Vec<Vec<u8>> = Vec::with_capacity(num_groups * num_passes);
269 for (group_idx, group_image) in group_images.iter().enumerate() {
270 for _pass in 0..num_passes {
271 let (_x_start, _y_start, _x_end, _y_end) = self.group_bounds(group_idx);
272
273 crate::trace::debug_eprintln!(
274 "MULTI_GROUP: Group {} bounds ({}, {}) - ({}, {}), size {}x{}",
275 group_idx,
276 _x_start,
277 _y_start,
278 _x_end,
279 _y_end,
280 group_image.width(),
281 group_image.height()
282 );
283
284 let mut group_writer = BitWriter::new();
285 write_group_modular_section(group_image, &global_state, &mut group_writer)?;
286 pass_group_data.push(group_writer.finish());
287
288 crate::trace::debug_eprintln!(
289 "MULTI_GROUP: PassGroup {} section = {} bytes",
290 group_idx,
291 pass_group_data.last().unwrap().len()
292 );
293 }
294 }
295
296 let mut section_sizes = Vec::with_capacity(2 + num_lf_groups + num_groups * num_passes);
300 section_sizes.push(lf_global_data.len());
301 for data in &lf_group_data {
302 section_sizes.push(data.len());
303 }
304 section_sizes.push(hf_global_data.len());
305 for data in &pass_group_data {
306 section_sizes.push(data.len());
307 }
308
309 crate::trace::debug_eprintln!(
310 "MULTI_GROUP: {} total sections, sizes = {:?}",
311 section_sizes.len(),
312 section_sizes
313 );
314
315 self.write_toc_multi(writer, §ion_sizes)?;
316
317 for byte in lf_global_data {
319 writer.write_u8(byte)?;
320 }
321 for data in lf_group_data {
322 for byte in data {
323 writer.write_u8(byte)?;
324 }
325 }
326 for byte in hf_global_data {
327 writer.write_u8(byte)?;
328 }
329 for data in pass_group_data {
330 for byte in data {
331 writer.write_u8(byte)?;
332 }
333 }
334
335 Ok(())
336 }
337
338 fn write_toc(&self, writer: &mut BitWriter, section_size: usize) -> Result<()> {
340 self.write_toc_multi(writer, &[section_size])
341 }
342
343 fn write_toc_multi(&self, writer: &mut BitWriter, section_sizes: &[usize]) -> Result<()> {
345 crate::trace::debug_eprintln!("TOC [bit {}]: Writing permuted = 0", writer.bits_written());
346 writer.write(1, 0)?;
348
349 crate::trace::debug_eprintln!(
350 "TOC [bit {}]: After permuted, byte aligning",
351 writer.bits_written()
352 );
353 writer.zero_pad_to_byte();
355
356 #[allow(clippy::unused_enumerate_index)]
358 for (_i, &size) in section_sizes.iter().enumerate() {
359 crate::trace::debug_eprintln!(
360 "TOC [bit {}]: Writing entry {} size={}",
361 writer.bits_written(),
362 _i,
363 size
364 );
365 self.write_toc_entry(writer, size as u32)?;
366 }
367 crate::trace::debug_eprintln!("TOC [bit {}]: After TOC entries", writer.bits_written());
368
369 writer.zero_pad_to_byte();
371
372 Ok(())
373 }
374
375 fn write_toc_entry(&self, writer: &mut BitWriter, size: u32) -> Result<()> {
377 if size < 1024 {
379 writer.write(2, 0)?; writer.write(10, size as u64)?;
381 } else if size < 17408 {
382 writer.write(2, 1)?; writer.write(14, (size - 1024) as u64)?;
384 } else if size < 4211712 {
385 writer.write(2, 2)?; writer.write(22, (size - 17408) as u64)?;
387 } else {
388 writer.write(2, 3)?; writer.write(30, (size - 4211712) as u64)?;
390 }
391 Ok(())
392 }
393
394 pub fn num_groups(&self) -> usize {
396 let num_groups_x = self.width.div_ceil(GROUP_DIM);
397 let num_groups_y = self.height.div_ceil(GROUP_DIM);
398 num_groups_x * num_groups_y
399 }
400
401 pub fn num_groups_x(&self) -> usize {
403 self.width.div_ceil(GROUP_DIM)
404 }
405
406 pub fn num_groups_y(&self) -> usize {
408 self.height.div_ceil(GROUP_DIM)
409 }
410
411 pub fn num_lf_groups(&self) -> usize {
414 let lf_group_dim = GROUP_DIM * 8; let lf_groups_x = self.width.div_ceil(lf_group_dim);
416 let lf_groups_y = self.height.div_ceil(lf_group_dim);
417 lf_groups_x * lf_groups_y
418 }
419
420 pub fn num_toc_entries(&self, num_passes: usize) -> usize {
424 let num_groups = self.num_groups();
425 if num_groups == 1 && num_passes == 1 {
426 1
427 } else {
428 2 + self.num_lf_groups() + num_groups * num_passes
429 }
430 }
431
432 pub fn group_bounds(&self, group_idx: usize) -> (usize, usize, usize, usize) {
435 let num_groups_x = self.num_groups_x();
436 let gx = group_idx % num_groups_x;
437 let gy = group_idx / num_groups_x;
438
439 let x_start = gx * GROUP_DIM;
440 let y_start = gy * GROUP_DIM;
441 let x_end = (x_start + GROUP_DIM).min(self.width);
442 let y_end = (y_start + GROUP_DIM).min(self.height);
443
444 (x_start, y_start, x_end, y_end)
445 }
446}
447
448#[cfg(test)]
449mod tests {
450 use super::*;
451
452 #[test]
453 fn test_frame_encoder_creation() {
454 let encoder = FrameEncoder::new(256, 256, FrameEncoderOptions::default());
455 assert_eq!(encoder.num_groups(), 1);
456 }
457
458 #[test]
459 fn test_frame_encoder_multi_group() {
460 let encoder = FrameEncoder::new(512, 512, FrameEncoderOptions::default());
461 assert_eq!(encoder.num_groups(), 4); assert_eq!(encoder.num_groups_x(), 2);
463 assert_eq!(encoder.num_groups_y(), 2);
464 assert_eq!(encoder.num_lf_groups(), 1); }
466
467 #[test]
468 fn test_group_bounds() {
469 let encoder = FrameEncoder::new(512, 512, FrameEncoderOptions::default());
470
471 let (x0, y0, x1, y1) = encoder.group_bounds(0);
473 assert_eq!((x0, y0, x1, y1), (0, 0, 256, 256));
474
475 let (x0, y0, x1, y1) = encoder.group_bounds(1);
477 assert_eq!((x0, y0, x1, y1), (256, 0, 512, 256));
478
479 let (x0, y0, x1, y1) = encoder.group_bounds(2);
481 assert_eq!((x0, y0, x1, y1), (0, 256, 256, 512));
482
483 let (x0, y0, x1, y1) = encoder.group_bounds(3);
485 assert_eq!((x0, y0, x1, y1), (256, 256, 512, 512));
486 }
487
488 #[test]
489 fn test_group_bounds_partial() {
490 let encoder = FrameEncoder::new(300, 200, FrameEncoderOptions::default());
492 assert_eq!(encoder.num_groups(), 2); let (x0, y0, x1, y1) = encoder.group_bounds(0);
495 assert_eq!((x0, y0, x1, y1), (0, 0, 256, 200));
496
497 let (x0, y0, x1, y1) = encoder.group_bounds(1);
498 assert_eq!((x0, y0, x1, y1), (256, 0, 300, 200)); }
500
501 #[test]
502 fn test_num_toc_entries() {
503 let encoder = FrameEncoder::new(256, 256, FrameEncoderOptions::default());
505 assert_eq!(encoder.num_toc_entries(1), 1);
506
507 let encoder = FrameEncoder::new(512, 512, FrameEncoderOptions::default());
509 assert_eq!(encoder.num_toc_entries(1), 7);
510
511 assert_eq!(encoder.num_toc_entries(2), 11);
513 }
514
515 #[test]
516 fn test_encode_multi_group_image() {
517 let mut data = Vec::with_capacity(300 * 300 * 3);
519 for y in 0..300 {
520 for x in 0..300 {
521 data.push(((x + y) % 256) as u8); data.push(((x * 2) % 256) as u8); data.push(((y * 2) % 256) as u8); }
526 }
527
528 let image = ModularImage::from_rgb8(&data, 300, 300).unwrap();
529
530 let encoder = FrameEncoder::new(300, 300, FrameEncoderOptions::default());
531 assert_eq!(encoder.num_groups(), 4); let mut writer = BitWriter::new();
534 let color_encoding = ColorEncoding::srgb();
535
536 encoder
537 .encode_modular(&image, &color_encoding, &mut writer)
538 .unwrap();
539
540 let bytes = writer.finish_with_padding();
541 crate::trace::debug_eprintln!("Multi-group modular: {} bytes", bytes.len());
542 assert!(!bytes.is_empty());
543 assert!(bytes.len() > 100); assert!(bytes.len() < 300 * 300 * 3); }
547
548 #[test]
549 fn test_encode_small_image() {
550 let mut data = Vec::with_capacity(4 * 4 * 3);
553 for y in 0..4 {
554 for x in 0..4 {
555 let v = if (x + y) % 2 == 0 { 0u8 } else { 128u8 };
556 data.push(v); data.push(v); data.push(v); }
560 }
561
562 let image = ModularImage::from_rgb8(&data, 4, 4).unwrap();
563
564 let encoder = FrameEncoder::new(4, 4, FrameEncoderOptions::default());
565 let mut writer = BitWriter::new();
566 let color_encoding = ColorEncoding::srgb();
567
568 encoder
569 .encode_modular(&image, &color_encoding, &mut writer)
570 .unwrap();
571
572 let bytes = writer.finish_with_padding();
573 assert!(!bytes.is_empty());
574 }
575}