msg_tool\scripts\bgi\image/
cbg.rs

1//! Buriko General Interpreter/Ethornell Compressed Image File
2use crate::ext::atomic::*;
3use crate::ext::io::*;
4use crate::scripts::base::*;
5use crate::types::*;
6use crate::utils::bit_stream::*;
7use crate::utils::img::*;
8use crate::utils::struct_pack::*;
9use anyhow::Result;
10use msg_tool_macro::*;
11use std::io::{Read, Seek, Write};
12use std::sync::atomic::AtomicBool;
13use std::sync::{Arc, Mutex};
14
15#[derive(Debug)]
16/// Builder for BGI Compressed Image scripts.
17pub struct BgiCBGBuilder {}
18
19impl BgiCBGBuilder {
20    /// Creates a new instance of `BgiCBGBuilder`.
21    pub const fn new() -> Self {
22        BgiCBGBuilder {}
23    }
24}
25
26impl ScriptBuilder for BgiCBGBuilder {
27    fn default_encoding(&self) -> Encoding {
28        Encoding::Cp932
29    }
30
31    fn build_script(
32        &self,
33        data: Vec<u8>,
34        _filename: &str,
35        _encoding: Encoding,
36        _archive_encoding: Encoding,
37        config: &ExtraConfig,
38        _archive: Option<&Box<dyn Script>>,
39    ) -> Result<Box<dyn Script>> {
40        Ok(Box::new(BgiCBG::new(data, config)?))
41    }
42
43    fn extensions(&self) -> &'static [&'static str] {
44        &[]
45    }
46
47    fn script_type(&self) -> &'static ScriptType {
48        &ScriptType::BGICbg
49    }
50
51    fn is_image(&self) -> bool {
52        true
53    }
54
55    fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
56        if buf_len >= 0x10 && buf.starts_with(b"CompressedBG___") {
57            return Some(255);
58        }
59        None
60    }
61
62    fn can_create_image_file(&self) -> bool {
63        true
64    }
65
66    fn create_image_file<'a>(
67        &'a self,
68        data: ImageData,
69        mut writer: Box<dyn WriteSeek + 'a>,
70        _options: &ExtraConfig,
71    ) -> Result<()> {
72        let encoder = CbgEncoder::new(data)?;
73        let data = encoder.encode()?;
74        writer.write_all(&data)?;
75        Ok(())
76    }
77}
78
79#[derive(Debug, StructPack, StructUnpack)]
80struct BgiCBGHeader {
81    width: u16,
82    height: u16,
83    bpp: u32,
84    _unk: u64,
85    intermediate_length: u32,
86    key: u32,
87    enc_length: u32,
88    check_sum: u8,
89    check_xor: u8,
90    version: u16,
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq)]
94enum CbgColorType {
95    Bgra32,
96    Bgr24,
97    Grayscale,
98    Bgr565,
99}
100
101fn convert_bgr565_to_bgr24(input: Vec<u8>, width: u16, height: u16) -> ImageData {
102    let pixel_count = width as usize * height as usize;
103    let mut output = Vec::with_capacity(pixel_count * 3);
104
105    for chunk in input.chunks_exact(2) {
106        let pixel = u16::from_le_bytes([chunk[0], chunk[1]]);
107
108        let blue_5bit = (pixel & 0x1) as u8;
109        let green_6bit = ((pixel >> 5) & 0x3) as u8;
110        let red_5bit = ((pixel >> 11) & 0x1) as u8;
111
112        let blue = ((blue_5bit as u16 * 255) / 31) as u8;
113        let green = ((green_6bit as u16 * 255) / 63) as u8;
114        let red = ((red_5bit as u16 * 255) / 31) as u8;
115
116        output.push(blue);
117        output.push(green);
118        output.push(red);
119    }
120
121    ImageData {
122        width: width as u32,
123        height: height as u32,
124        color_type: ImageColorType::Bgr,
125        depth: 8,
126        data: output,
127    }
128}
129
130#[derive(Debug)]
131/// BGI Compressed Image script.
132pub struct BgiCBG {
133    header: BgiCBGHeader,
134    data: MemReader,
135    color_type: CbgColorType,
136}
137
138impl BgiCBG {
139    /// Creates a new instance of `BgiCBG` from a buffer.
140    ///
141    /// * `data` - The buffer containing the script data.
142    /// * `config` - Extra configuration options.
143    pub fn new(data: Vec<u8>, _config: &ExtraConfig) -> Result<Self> {
144        let mut reader = MemReader::new(data);
145        let mut magic = [0u8; 16];
146        reader.read_exact(&mut magic)?;
147        if !magic.starts_with(b"CompressedBG___") {
148            return Err(anyhow::anyhow!("Invalid magic: {:?}", magic));
149        }
150        let header = BgiCBGHeader::unpack(&mut reader, false, Encoding::Cp932)?;
151        if header.version > 2 {
152            return Err(anyhow::anyhow!("Unsupported version: {}", header.version));
153        }
154        let color_type = match header.bpp {
155            32 => CbgColorType::Bgra32,
156            24 => CbgColorType::Bgr24,
157            8 => CbgColorType::Grayscale,
158            16 => {
159                if header.version == 2 {
160                    return Err(anyhow::anyhow!("Unsupported BPP 16 in version 2"));
161                }
162                CbgColorType::Bgr565
163            }
164            _ => return Err(anyhow::anyhow!("Unsupported BPP: {}", header.bpp)),
165        };
166        Ok(BgiCBG {
167            header,
168            data: reader,
169            color_type,
170        })
171    }
172}
173
174impl Script for BgiCBG {
175    fn default_output_script_type(&self) -> OutputScriptType {
176        OutputScriptType::Json
177    }
178
179    fn default_format_type(&self) -> FormatOptions {
180        FormatOptions::None
181    }
182
183    fn is_image(&self) -> bool {
184        true
185    }
186
187    fn export_image(&self) -> Result<ImageData> {
188        let decoder = CbgDecoder::new(self.data.to_ref(), &self.header, self.color_type)?;
189        Ok(decoder.unpack()?)
190    }
191
192    fn import_image<'a>(
193        &'a self,
194        data: ImageData,
195        mut file: Box<dyn WriteSeek + 'a>,
196    ) -> Result<()> {
197        let encoder = CbgEncoder::new(data)?;
198        let encoded_data = encoder.encode()?;
199        file.write_all(&encoded_data)?;
200        Ok(())
201    }
202}
203
204struct CbgDecoder<'a> {
205    stream: MsbBitStream<MemReaderRef<'a>>,
206    info: &'a BgiCBGHeader,
207    color_type: CbgColorType,
208    key: u32,
209    magic: u32,
210    pixel_size: u8,
211    stride: usize,
212}
213
214impl<'a> CbgDecoder<'a> {
215    fn new(
216        reader: MemReaderRef<'a>,
217        info: &'a BgiCBGHeader,
218        color_type: CbgColorType,
219    ) -> Result<Self> {
220        let magic = 0;
221        let key = info.key;
222        let stream = MsbBitStream::new(reader);
223        let pixel_size = info.bpp as u8 / 8;
224        let stride = info.width as usize * (info.bpp as usize / 8);
225        Ok(CbgDecoder {
226            stream,
227            info,
228            key,
229            magic,
230            color_type,
231            pixel_size,
232            stride,
233        })
234    }
235
236    fn unpack(mut self) -> Result<ImageData> {
237        self.stream.m_input.pos = 0x30;
238        if self.info.version < 2 {
239            return self.unpack_v1();
240        } else if self.info.version == 2 {
241            if self.info.enc_length < 0x80 {
242                return Err(anyhow::anyhow!(
243                    "Invalid encoded length: {}",
244                    self.info.enc_length
245                ));
246            }
247            return self.unpack_v2();
248        }
249        Err(anyhow::anyhow!("Unknown version: {}", self.info.version))
250    }
251
252    fn unpack_v1(&mut self) -> Result<ImageData> {
253        let leaf_nodes_weight = {
254            let stream = MemReader::new(self.read_encoded()?);
255            let mut stream_ref = stream.to_ref();
256            Self::read_weight_table(&mut stream_ref, 0x100)?
257        };
258        let tree = HuffmanTree::new(&leaf_nodes_weight, false);
259        let mut packed = Vec::with_capacity(self.info.intermediate_length as usize);
260        packed.resize(self.info.intermediate_length as usize, 0);
261        self.huffman_decompress(&tree, &mut packed)?;
262        let buf_size = self.stride * self.info.height as usize;
263        let mut output = Vec::with_capacity(buf_size);
264        output.resize(buf_size, 0);
265        Self::unpack_zeros(&packed, &mut output);
266        self.reverse_average_sampling(&mut output);
267        let color_type = match self.color_type {
268            CbgColorType::Bgra32 => ImageColorType::Bgra,
269            CbgColorType::Bgr24 => ImageColorType::Bgr,
270            CbgColorType::Grayscale => ImageColorType::Grayscale,
271            CbgColorType::Bgr565 => {
272                return Ok(convert_bgr565_to_bgr24(
273                    output,
274                    self.info.width,
275                    self.info.height,
276                ));
277            }
278        };
279        Ok(ImageData {
280            width: self.info.width as u32,
281            height: self.info.height as u32,
282            color_type,
283            depth: 8,
284            data: output,
285        })
286    }
287
288    fn unpack_v2(&mut self) -> Result<ImageData> {
289        let dct_data = self.read_encoded()?;
290        let mut dct = [[0.0f32; 64]; 2];
291        for i in 0..0x80 {
292            dct[i >> 6][i & 0x3f] = dct_data[i] as f32 * DCT_TABLE[i & 0x3f];
293        }
294
295        let base_offset = self.stream.m_input.pos;
296        let tree1 = HuffmanTree::new(
297            &Self::read_weight_table(&mut self.stream.m_input, 0x10)?,
298            true,
299        );
300        let tree2 = HuffmanTree::new(
301            &Self::read_weight_table(&mut self.stream.m_input, 0xB0)?,
302            true,
303        );
304
305        let width = ((self.info.width as i32 + 7) & -8) as i32;
306        let height = ((self.info.height as i32 + 7) & -8) as i32;
307        let y_blocks = height / 8;
308
309        let mut offsets = Vec::with_capacity((y_blocks + 1) as usize);
310        let input_base =
311            (self.stream.m_input.pos + ((y_blocks + 1) as usize * 4) - base_offset) as i32;
312
313        for _ in 0..=y_blocks {
314            let offset = self.stream.m_input.read_i32()?;
315            offsets.push(offset - input_base);
316        }
317
318        let input = self.stream.m_input.data[self.stream.m_input.pos..].to_vec();
319        let pad_skip = ((width >> 3) + 7) >> 3;
320
321        let output_size = (width * height * 4) as usize;
322        let output = vec![0u8; output_size];
323        let output_mutex = Mutex::new(output);
324
325        let decoder = Arc::new(ParallelCbgDecoder {
326            input,
327            output: output_mutex,
328            bpp: self.info.bpp as i32,
329            width,
330            height,
331            tree1,
332            tree2,
333            dct,
334            has_alpha: AtomicBool::new(false),
335        });
336
337        let mut tasks = Vec::new();
338        let mut dst = 0i32;
339
340        for i in 0..y_blocks {
341            let block_offset = offsets[i as usize] + pad_skip;
342            let next_offset = if i + 1 == y_blocks {
343                decoder.input.len() as i32
344            } else {
345                offsets[(i + 1) as usize]
346            };
347            let closure_dst = dst;
348            let decoder_ref = Arc::clone(&decoder);
349
350            let task = std::thread::spawn(move || {
351                decoder_ref.unpack_block(block_offset, next_offset - block_offset, closure_dst)
352            });
353            tasks.push(task);
354            dst += width * 32;
355        }
356
357        if self.info.bpp == 32 {
358            let decoder_ref = Arc::clone(&decoder);
359            let task =
360                std::thread::spawn(move || decoder_ref.unpack_alpha(offsets[y_blocks as usize]));
361            tasks.push(task);
362        }
363
364        for task in tasks {
365            task.join()
366                .map_err(|e| anyhow::anyhow!("Thread join failed: {:?}", e))??;
367        }
368
369        let has_alpha = decoder.has_alpha.qload();
370        let mut output = decoder
371            .output
372            .lock()
373            .map_err(|e| anyhow::anyhow!("Failed to lock output: {}", e))?
374            .clone();
375
376        if !has_alpha {
377            let mut src_idx = 0;
378            let mut dst_idx = 0;
379            for _ in 0..self.info.height {
380                for _ in 0..self.info.width {
381                    output[dst_idx] = output[src_idx];
382                    output[dst_idx + 1] = output[src_idx + 1];
383                    output[dst_idx + 2] = output[src_idx + 2];
384                    src_idx += 4;
385                    dst_idx += 3;
386                }
387            }
388            output.truncate(dst_idx);
389        }
390
391        let color_type = if has_alpha {
392            ImageColorType::Bgra
393        } else {
394            ImageColorType::Bgr
395        };
396
397        Ok(ImageData {
398            width: decoder.width as u32,
399            height: decoder.height as u32,
400            color_type,
401            depth: 8,
402            data: output,
403        })
404    }
405
406    fn read_encoded(&mut self) -> Result<Vec<u8>> {
407        let mut output = Vec::with_capacity(self.info.enc_length as usize);
408        output.resize(self.info.enc_length as usize, 0);
409        self.stream.m_input.read_exact(&mut output)?;
410        let mut sum = 0u8;
411        let mut xor = 0u8;
412        for i in 0..output.len() {
413            output[i] = output[i].wrapping_sub(self.update_key());
414            sum = sum.wrapping_add(output[i]);
415            xor ^= output[i];
416        }
417        if sum != self.info.check_sum || xor != self.info.check_xor {
418            return Err(anyhow::anyhow!(
419                "Checksum mismatch: sum={}, xor={}",
420                sum,
421                xor
422            ));
423        }
424        Ok(output)
425    }
426
427    fn read_int(input: &mut MemReaderRef<'_>) -> Result<i32> {
428        let mut v = 0;
429        let mut code_length = 0;
430        loop {
431            let code = input.read_i8()?;
432            if code_length >= 32 {
433                return Err(anyhow::anyhow!(
434                    "Failed to raed int: code={}, code_length={}",
435                    code,
436                    code_length
437                ));
438            }
439            v |= ((code & 0x7f) as i32) << code_length;
440            code_length += 7;
441            if code & -128 == 0 {
442                break;
443            }
444        }
445        Ok(v)
446    }
447
448    fn read_weight_table(input: &mut MemReaderRef<'_>, length: usize) -> Result<Vec<u32>> {
449        let mut weights = Vec::with_capacity(length);
450        for _ in 0..length {
451            let weight = Self::read_int(input)? as u32;
452            weights.push(weight);
453        }
454        Ok(weights)
455    }
456
457    fn huffman_decompress(&mut self, tree: &HuffmanTree, output: &mut [u8]) -> Result<()> {
458        for dst in 0..output.len() {
459            output[dst] = tree.decode_token(&mut self.stream)? as u8;
460        }
461        Ok(())
462    }
463
464    fn unpack_zeros(input: &[u8], output: &mut [u8]) {
465        let mut dst = 0;
466        let mut dec_zero = 0;
467        let mut src = 0;
468        while dst < output.len() {
469            let mut code_length = 0;
470            let mut count = 0;
471            let mut code;
472            loop {
473                if src >= input.len() {
474                    return;
475                }
476                code = input[src];
477                src += 1;
478                count |= ((code & 0x7f) as usize) << code_length;
479                code_length += 7;
480                if code & 0x80 == 0 {
481                    break;
482                }
483            }
484            if dst + count > output.len() {
485                break;
486            }
487            if dec_zero == 0 {
488                if src + count > input.len() {
489                    break;
490                }
491                output[dst..dst + count].copy_from_slice(&input[src..src + count]);
492                src += count;
493            } else {
494                for i in 0..count {
495                    output[dst + i] = 0;
496                }
497            }
498            dec_zero ^= 1;
499            dst += count;
500        }
501    }
502
503    fn reverse_average_sampling(&self, output: &mut [u8]) {
504        for y in 0..self.info.height {
505            let line = y as usize * self.stride;
506            for x in 0..self.info.width {
507                let pixel = line + x as usize * self.pixel_size as usize;
508                for p in 0..self.pixel_size {
509                    let mut avg = 0u32;
510                    if x > 0 {
511                        avg = avg.wrapping_add(
512                            output[pixel + p as usize - self.pixel_size as usize] as u32,
513                        );
514                    }
515                    if y > 0 {
516                        avg = avg.wrapping_add(output[pixel + p as usize - self.stride] as u32);
517                    }
518                    if x > 0 && y > 0 {
519                        avg /= 2;
520                    }
521                    if avg != 0 {
522                        output[pixel + p as usize] =
523                            output[pixel + p as usize].wrapping_add(avg as u8);
524                    }
525                }
526            }
527        }
528    }
529
530    fn update_key(&mut self) -> u8 {
531        let v0 = 20021 * (self.key & 0xffff);
532        let mut v1 = self.magic | (self.key >> 16);
533        v1 = v1
534            .overflowing_mul(20021)
535            .0
536            .overflowing_add(self.key.overflowing_mul(346).0)
537            .0;
538        v1 = (v1 + (v0 >> 16)) & 0xffff;
539        self.key = (v1 << 16) + (v0 & 0xffff) + 1;
540        v1 as u8
541    }
542}
543
544#[derive(Debug)]
545struct HuffmanNode {
546    valid: bool,
547    is_parent: bool,
548    weight: u32,
549    left_index: usize,
550    right_index: usize,
551}
552
553#[derive(Debug)]
554struct HuffmanTree {
555    nodes: Vec<HuffmanNode>,
556}
557
558impl HuffmanTree {
559    fn new(weights: &[u32], v2: bool) -> Self {
560        let mut nodes = Vec::with_capacity(weights.len() * 2);
561        let mut root_node_weight = 0u32;
562        for weight in weights {
563            let node = HuffmanNode {
564                valid: *weight != 0,
565                is_parent: false,
566                weight: *weight,
567                left_index: 0,
568                right_index: 0,
569            };
570            nodes.push(node);
571            root_node_weight = root_node_weight.wrapping_add(*weight);
572        }
573        let mut child_node_index = [0usize; 2];
574        loop {
575            let mut weight = 0u32;
576            for i in 0usize..2usize {
577                let mut min_weight = u32::MAX;
578                child_node_index[i] = usize::MAX;
579                let mut n = 0;
580                if v2 {
581                    while n < nodes.len() {
582                        if nodes[n].valid {
583                            min_weight = nodes[n].weight;
584                            child_node_index[i] = n;
585                            n += 1;
586                            break;
587                        }
588                        n += 1;
589                    }
590                    n = n.max(i + 1);
591                }
592                while n < nodes.len() {
593                    if nodes[n].valid && nodes[n].weight < min_weight {
594                        min_weight = nodes[n].weight;
595                        child_node_index[i] = n;
596                    }
597                    n += 1;
598                }
599                if child_node_index[i] == usize::MAX {
600                    continue;
601                }
602                nodes[child_node_index[i]].valid = false;
603                weight = weight.wrapping_add(nodes[child_node_index[i]].weight);
604            }
605            let parent_node = HuffmanNode {
606                valid: true,
607                is_parent: true,
608                left_index: child_node_index[0],
609                right_index: child_node_index[1],
610                weight,
611            };
612            nodes.push(parent_node);
613            if weight >= root_node_weight {
614                break;
615            }
616        }
617        Self { nodes }
618    }
619
620    fn decode_token(&self, stream: &mut MsbBitStream<MemReaderRef<'_>>) -> Result<usize> {
621        let mut node_index = self.nodes.len() - 1;
622        loop {
623            let bit = stream.get_next_bit()?;
624            if !bit {
625                node_index = self.nodes[node_index].left_index;
626            } else {
627                node_index = self.nodes[node_index].right_index;
628            }
629            if !self.nodes[node_index].is_parent {
630                return Ok(node_index);
631            }
632        }
633    }
634
635    fn encode_token(&self, stream: &mut MsbBitWriter<impl Write>, token: usize) -> Result<()> {
636        let mut path = Vec::new();
637        if !self.find_path(self.nodes.len() - 1, token, &mut path) {
638            return Err(anyhow::anyhow!("Token not found in Huffman tree"));
639        }
640        for &bit in path.iter().rev() {
641            stream.put_bit(bit)?;
642        }
643        Ok(())
644    }
645
646    fn find_path(&self, node_index: usize, token: usize, path: &mut Vec<bool>) -> bool {
647        if node_index == usize::MAX {
648            return false;
649        }
650        let node = &self.nodes[node_index];
651        if !node.is_parent {
652            return node_index == token;
653        }
654
655        if self.find_path(node.left_index, token, path) {
656            path.push(false);
657            return true;
658        }
659        if self.find_path(node.right_index, token, path) {
660            path.push(true);
661            return true;
662        }
663        false
664    }
665}
666
667const DCT_TABLE: [f32; 64] = [
668    1.00000000, 1.38703990, 1.30656302, 1.17587554, 1.00000000, 0.78569496, 0.54119611, 0.27589938,
669    1.38703990, 1.92387950, 1.81225491, 1.63098633, 1.38703990, 1.08979023, 0.75066054, 0.38268343,
670    1.30656302, 1.81225491, 1.70710683, 1.53635550, 1.30656302, 1.02655995, 0.70710677, 0.36047992,
671    1.17587554, 1.63098633, 1.53635550, 1.38268340, 1.17587554, 0.92387950, 0.63637930, 0.32442334,
672    1.00000000, 1.38703990, 1.30656302, 1.17587554, 1.00000000, 0.78569496, 0.54119611, 0.27589938,
673    0.78569496, 1.08979023, 1.02655995, 0.92387950, 0.78569496, 0.61731654, 0.42521504, 0.21677275,
674    0.54119611, 0.75066054, 0.70710677, 0.63637930, 0.54119611, 0.42521504, 0.29289323, 0.14931567,
675    0.27589938, 0.38268343, 0.36047992, 0.32442334, 0.27589938, 0.21677275, 0.14931567, 0.07612047,
676];
677
678const BLOCK_FILL_ORDER: [u8; 64] = [
679    0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20,
680    13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59,
681    52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
682];
683
684struct ParallelCbgDecoder {
685    input: Vec<u8>,
686    output: Mutex<Vec<u8>>,
687    bpp: i32,
688    width: i32,
689    height: i32,
690    tree1: HuffmanTree,
691    tree2: HuffmanTree,
692    dct: [[f32; 64]; 2],
693    has_alpha: AtomicBool,
694}
695
696impl ParallelCbgDecoder {
697    fn unpack_block(&self, offset: i32, length: i32, dst: i32) -> Result<()> {
698        let input = MemReaderRef::new(&self.input[offset as usize..(offset + length) as usize]);
699        let mut reader = MsbBitStream::new(input);
700
701        let block_size = CbgDecoder::read_int(&mut reader.m_input)?;
702        if block_size == -1 {
703            return Ok(());
704        }
705
706        let mut color_data = vec![0i16; block_size as usize];
707        let mut acc = 0i32;
708        let mut i = 0i32;
709
710        while i < block_size && reader.m_input.pos < reader.m_input.data.len() {
711            let count = self.tree1.decode_token(&mut reader)?;
712            if count != 0 {
713                let mut v = reader.get_bits(count as u32)? as i32;
714                if (v >> (count - 1)) == 0 {
715                    v = (-1 << count | v) + 1;
716                }
717                acc += v;
718            }
719            color_data[i as usize] = acc as i16;
720            i += 64;
721        }
722
723        if (reader.m_cached_bits & 7) != 0 {
724            reader.get_bits(reader.m_cached_bits & 7)?;
725        }
726
727        i = 0;
728        while i < block_size && reader.m_input.pos < reader.m_input.data.len() {
729            let mut index = 1usize;
730            while index < 64 && reader.m_input.pos < reader.m_input.data.len() {
731                let code = self.tree2.decode_token(&mut reader)?;
732                if code == 0 {
733                    break;
734                }
735                if code == 0xf {
736                    index += 0x10;
737                    continue;
738                }
739                index += code & 0xf;
740                if index >= BLOCK_FILL_ORDER.len() {
741                    break;
742                }
743                let bits = code >> 4;
744                let mut v = reader.get_bits(bits as u32)? as i32;
745                if bits != 0 && (v >> (bits - 1)) == 0 {
746                    v = (-1 << bits | v) + 1;
747                }
748                color_data[i as usize + BLOCK_FILL_ORDER[index] as usize] = v as i16;
749                index += 1;
750            }
751            i += 64;
752        }
753
754        if self.bpp == 8 {
755            self.decode_grayscale(&color_data, dst)?;
756        } else {
757            self.decode_rgb(&color_data, dst)?;
758        }
759
760        Ok(())
761    }
762
763    fn decode_rgb(&self, data: &[i16], dst: i32) -> Result<()> {
764        let block_count = self.width / 8;
765        let mut dst = dst as usize;
766
767        for i in 0..block_count {
768            let mut src = (i * 64) as usize;
769            let mut ycbcr_block = [[0i16; 3]; 64];
770
771            for channel in 0..3 {
772                self.decode_dct(channel, data, src, &mut ycbcr_block)?;
773                src += (self.width * 8) as usize;
774            }
775
776            let mut output = self
777                .output
778                .lock()
779                .map_err(|e| anyhow::anyhow!("Failed to lock output: {}", e))?;
780
781            for j in 0..64 {
782                let cy = ycbcr_block[j][0] as f32;
783                let cb = ycbcr_block[j][1] as f32;
784                let cr = ycbcr_block[j][2] as f32;
785
786                // Full-range YCbCr->RGB conversion
787                let r = cy + 1.402f32 * cr - 178.956f32;
788                let g = cy - 0.34414f32 * cb - 0.71414f32 * cr + 135.95984f32;
789                let b = cy + 1.772f32 * cb - 226.316f32;
790
791                let y = j >> 3;
792                let x = j & 7;
793                let p = (y * self.width as usize + x) * 4 + dst;
794
795                output[p] = Self::float_to_byte(b);
796                output[p + 1] = Self::float_to_byte(g);
797                output[p + 2] = Self::float_to_byte(r);
798            }
799            dst += 32;
800        }
801        Ok(())
802    }
803
804    fn decode_grayscale(&self, data: &[i16], dst: i32) -> Result<()> {
805        let mut src = 0;
806        let block_count = self.width / 8;
807        let mut dst = dst as usize;
808
809        for _ in 0..block_count {
810            let mut ycbcr_block = [[0i16; 3]; 64];
811            self.decode_dct(0, data, src, &mut ycbcr_block)?;
812            src += 64;
813
814            let mut output = self
815                .output
816                .lock()
817                .map_err(|e| anyhow::anyhow!("Failed to lock output: {}", e))?;
818
819            for j in 0..64 {
820                let y = j >> 3;
821                let x = j & 7;
822                let p = (y * self.width as usize + x) * 4 + dst;
823                let value = ycbcr_block[j][0] as u8;
824
825                output[p] = value;
826                output[p + 1] = value;
827                output[p + 2] = value;
828            }
829            dst += 32;
830        }
831        Ok(())
832    }
833
834    fn unpack_alpha(&self, offset: i32) -> Result<()> {
835        let mut input = MemReaderRef::new(&self.input[offset as usize..]);
836
837        if input.read_i32()? != 1 {
838            return Ok(());
839        }
840
841        let mut dst = 3;
842        let mut ctl = 1i32 << 1;
843
844        let mut output = self
845            .output
846            .lock()
847            .map_err(|e| anyhow::anyhow!("Failed to lock output: {}", e))?;
848
849        while dst < output.len() {
850            ctl >>= 1;
851            if ctl == 1 {
852                ctl = (input.read_u8()? as i32) | 0x100;
853            }
854
855            if (ctl & 1) != 0 {
856                let v = input.read_u16()? as i32;
857                let mut x = v & 0x3f;
858                if x > 0x1f {
859                    x |= -0x40;
860                }
861                let mut y = (v >> 6) & 7;
862                if y != 0 {
863                    y |= -8;
864                }
865                let count = ((v >> 9) & 0x7f) + 3;
866
867                let src = dst as isize + (x as isize + y as isize * self.width as isize) * 4;
868                if src < 0 || src >= dst as isize {
869                    return Ok(());
870                }
871
872                let mut src = src as usize;
873                for _ in 0..count {
874                    output[dst] = output[src];
875                    src += 4;
876                    dst += 4;
877                }
878            } else {
879                output[dst] = input.read_u8()?;
880                dst += 4;
881            }
882        }
883
884        self.has_alpha.qsave(true);
885        Ok(())
886    }
887
888    fn decode_dct(
889        &self,
890        channel: usize,
891        data: &[i16],
892        src: usize,
893        output: &mut [[i16; 3]; 64],
894    ) -> Result<()> {
895        let d = if channel > 0 { 1 } else { 0 };
896        let mut tmp = [[0f32; 8]; 8];
897
898        for i in 0..8 {
899            // Check if all AC coefficients are zero
900            if data[src + 8 + i] == 0
901                && data[src + 16 + i] == 0
902                && data[src + 24 + i] == 0
903                && data[src + 32 + i] == 0
904                && data[src + 40 + i] == 0
905                && data[src + 48 + i] == 0
906                && data[src + 56 + i] == 0
907            {
908                let t = data[src + i] as f32 * self.dct[d][i];
909                for row in 0..8 {
910                    tmp[row][i] = t;
911                }
912                continue;
913            }
914
915            let v1 = data[src + i] as f32 * self.dct[d][i];
916            let v2 = data[src + 8 + i] as f32 * self.dct[d][8 + i];
917            let v3 = data[src + 16 + i] as f32 * self.dct[d][16 + i];
918            let v4 = data[src + 24 + i] as f32 * self.dct[d][24 + i];
919            let v5 = data[src + 32 + i] as f32 * self.dct[d][32 + i];
920            let v6 = data[src + 40 + i] as f32 * self.dct[d][40 + i];
921            let v7 = data[src + 48 + i] as f32 * self.dct[d][48 + i];
922            let v8 = data[src + 56 + i] as f32 * self.dct[d][56 + i];
923
924            let v10 = v1 + v5;
925            let v11 = v1 - v5;
926            let v12 = v3 + v7;
927            let v13 = (v3 - v7) * 1.414213562f32 - v12;
928            let v1 = v10 + v12;
929            let v7 = v10 - v12;
930            let v3 = v11 + v13;
931            let v5 = v11 - v13;
932            let v14 = v2 + v8;
933            let v15 = v2 - v8;
934            let v16 = v6 + v4;
935            let v17 = v6 - v4;
936            let v8 = v14 + v16;
937            let v11 = (v14 - v16) * 1.414213562f32;
938            let v9 = (v17 + v15) * 1.847759065f32;
939            let v10 = 1.082392200f32 * v15 - v9;
940            let v13 = -2.613125930f32 * v17 + v9;
941            let v6 = v13 - v8;
942            let v4 = v11 - v6;
943            let v2 = v10 + v4;
944
945            tmp[0][i] = v1 + v8;
946            tmp[1][i] = v3 + v6;
947            tmp[2][i] = v5 + v4;
948            tmp[3][i] = v7 - v2;
949            tmp[4][i] = v7 + v2;
950            tmp[5][i] = v5 - v4;
951            tmp[6][i] = v3 - v6;
952            tmp[7][i] = v1 - v8;
953        }
954
955        let mut dst = 0;
956        for i in 0..8 {
957            let v10 = tmp[i][0] + tmp[i][4];
958            let v11 = tmp[i][0] - tmp[i][4];
959            let v12 = tmp[i][2] + tmp[i][6];
960            let v13 = tmp[i][2] - tmp[i][6];
961            let v14 = tmp[i][1] + tmp[i][7];
962            let v15 = tmp[i][1] - tmp[i][7];
963            let v16 = tmp[i][5] + tmp[i][3];
964            let v17 = tmp[i][5] - tmp[i][3];
965
966            let v13 = 1.414213562f32 * v13 - v12;
967            let v1 = v10 + v12;
968            let v7 = v10 - v12;
969            let v3 = v11 + v13;
970            let v5 = v11 - v13;
971            let v8 = v14 + v16;
972            let v11 = (v14 - v16) * 1.414213562f32;
973            let v9 = (v17 + v15) * 1.847759065f32;
974            let v10 = v9 - v15 * 1.082392200f32;
975            let v13 = v9 - v17 * 2.613125930f32;
976            let v6 = v13 - v8;
977            let v4 = v11 - v6;
978            let v2 = v10 - v4;
979
980            output[dst][channel] = Self::float_to_short(v1 + v8);
981            output[dst + 1][channel] = Self::float_to_short(v3 + v6);
982            output[dst + 2][channel] = Self::float_to_short(v5 + v4);
983            output[dst + 3][channel] = Self::float_to_short(v7 + v2);
984            output[dst + 4][channel] = Self::float_to_short(v7 - v2);
985            output[dst + 5][channel] = Self::float_to_short(v5 - v4);
986            output[dst + 6][channel] = Self::float_to_short(v3 - v6);
987            output[dst + 7][channel] = Self::float_to_short(v1 - v8);
988            dst += 8;
989        }
990
991        Ok(())
992    }
993
994    fn float_to_short(f: f32) -> i16 {
995        let a = 0x80 + ((f as i32) >> 3);
996        if a <= 0 {
997            0
998        } else if a <= 0xff {
999            a as i16
1000        } else if a < 0x180 {
1001            0xff
1002        } else {
1003            0
1004        }
1005    }
1006
1007    fn float_to_byte(f: f32) -> u8 {
1008        if f >= 255.0 {
1009            0xff
1010        } else if f <= 0.0 {
1011            0
1012        } else {
1013            f as u8
1014        }
1015    }
1016}
1017
1018struct CbgEncoder {
1019    header: BgiCBGHeader,
1020    stream: MemWriter,
1021    img: ImageData,
1022    key: u32,
1023    magic: u32,
1024}
1025
1026impl CbgEncoder {
1027    pub fn new(mut img: ImageData) -> Result<Self> {
1028        if img.depth != 8 {
1029            return Err(anyhow::anyhow!("Unsupported image depth: {}", img.depth));
1030        }
1031        let bpp = match img.color_type {
1032            ImageColorType::Bgr => 24,
1033            ImageColorType::Bgra => 32,
1034            ImageColorType::Grayscale => 8,
1035            ImageColorType::Rgb => {
1036                convert_rgb_to_bgr(&mut img)?;
1037                24
1038            }
1039            ImageColorType::Rgba => {
1040                convert_rgba_to_bgra(&mut img)?;
1041                32
1042            }
1043        };
1044        let key = rand::random();
1045        let header = BgiCBGHeader {
1046            width: img.width as u16,
1047            height: img.height as u16,
1048            bpp,
1049            _unk: 0,
1050            intermediate_length: 0,
1051            key,
1052            enc_length: 0,
1053            check_sum: 0,
1054            check_xor: 0,
1055            version: 1,
1056        };
1057
1058        Ok(CbgEncoder {
1059            header,
1060            stream: MemWriter::new(),
1061            img,
1062            key,
1063            magic: 0,
1064        })
1065    }
1066
1067    pub fn encode(mut self) -> Result<Vec<u8>> {
1068        self.stream.write_all(b"CompressedBG___\0")?;
1069        let header_pos = self.stream.pos;
1070        self.stream.seek(std::io::SeekFrom::Current(0x20))?;
1071
1072        let pixel_size = (self.header.bpp / 8) as usize;
1073        let stride = self.header.width as usize * pixel_size;
1074        let mut sampled_data = self.img.data.clone();
1075        self.average_sampling(&mut sampled_data, stride, pixel_size);
1076
1077        let packed_data = Self::pack_zeros(&sampled_data);
1078        self.header.intermediate_length = packed_data.len() as u32;
1079
1080        let mut frequencies = vec![0u32; 256];
1081        for &byte in &packed_data {
1082            frequencies[byte as usize] += 1;
1083        }
1084        if frequencies.iter().all(|&f| f == 0) {
1085            frequencies[0] = 1;
1086        }
1087
1088        let tree = HuffmanTree::new(&frequencies, false);
1089
1090        let mut weight_writer = MemWriter::new();
1091        for &weight in &frequencies {
1092            Self::write_int(&mut weight_writer, weight as i32)?;
1093        }
1094        let weight_data = weight_writer.into_inner();
1095        self.write_encoded(&weight_data)?;
1096
1097        let mut bit_writer = MsbBitWriter::new(&mut self.stream);
1098        for &byte in &packed_data {
1099            tree.encode_token(&mut bit_writer, byte as usize)?;
1100        }
1101        bit_writer.flush()?;
1102
1103        let final_pos = self.stream.pos;
1104        self.stream.pos = header_pos;
1105        self.header.pack(&mut self.stream, false, Encoding::Cp932)?;
1106        self.stream.pos = final_pos;
1107
1108        Ok(self.stream.into_inner())
1109    }
1110
1111    fn average_sampling(&self, data: &mut [u8], stride: usize, pixel_size: usize) {
1112        for y in (0..self.header.height as usize).rev() {
1113            let line = y * stride;
1114            for x in (0..self.header.width as usize).rev() {
1115                let pixel = line + x * pixel_size;
1116                for p in 0..pixel_size {
1117                    let mut avg = 0u32;
1118                    let mut count = 0;
1119                    if x > 0 {
1120                        avg = avg.wrapping_add(data[pixel + p - pixel_size] as u32);
1121                        count += 1;
1122                    }
1123                    if y > 0 {
1124                        avg = avg.wrapping_add(data[pixel + p - stride] as u32);
1125                        count += 1;
1126                    }
1127                    if count > 0 {
1128                        avg /= count;
1129                    }
1130                    if avg != 0 {
1131                        data[pixel + p] = data[pixel + p].wrapping_sub(avg as u8);
1132                    }
1133                }
1134            }
1135        }
1136    }
1137
1138    fn pack_zeros(input: &[u8]) -> Vec<u8> {
1139        let mut output = Vec::new();
1140        let mut i = 0;
1141        let mut is_zero_run = false;
1142
1143        while i < input.len() {
1144            let mut count = 0;
1145            if is_zero_run {
1146                while i + count < input.len() && input[i + count] == 0 {
1147                    count += 1;
1148                }
1149            } else {
1150                while i + count < input.len() && input[i + count] != 0 {
1151                    count += 1;
1152                }
1153            }
1154
1155            let mut count_buf = Vec::new();
1156            let mut n = count;
1157            loop {
1158                let mut byte = (n & 0x7f) as u8;
1159                n >>= 7;
1160                if n > 0 {
1161                    byte |= 0x80;
1162                }
1163                count_buf.push(byte);
1164                if n == 0 {
1165                    break;
1166                }
1167            }
1168            output.extend_from_slice(&count_buf);
1169
1170            if !is_zero_run {
1171                output.extend_from_slice(&input[i..i + count]);
1172            }
1173            i += count;
1174            is_zero_run = !is_zero_run;
1175        }
1176        output
1177    }
1178
1179    fn write_int<W: Write>(writer: &mut W, mut value: i32) -> Result<()> {
1180        loop {
1181            let mut b = (value as u8) & 0x7f;
1182            value >>= 7;
1183            if value != 0 {
1184                b |= 0x80;
1185            }
1186            writer.write_u8(b)?;
1187            if value == 0 {
1188                break;
1189            }
1190        }
1191        Ok(())
1192    }
1193
1194    fn write_encoded(&mut self, data: &[u8]) -> Result<()> {
1195        self.header.enc_length = data.len() as u32;
1196        let mut sum = 0u8;
1197        let mut xor = 0u8;
1198        let mut encoded_data = Vec::with_capacity(data.len());
1199        for &byte in data {
1200            let encrypted_byte = byte.wrapping_add(self.update_key());
1201            sum = sum.wrapping_add(byte);
1202            xor ^= byte;
1203            encoded_data.push(encrypted_byte);
1204        }
1205        self.header.check_sum = sum;
1206        self.header.check_xor = xor;
1207        self.stream.write_all(&encoded_data)?;
1208        Ok(())
1209    }
1210
1211    fn update_key(&mut self) -> u8 {
1212        let v0 = 20021 * (self.key & 0xffff);
1213        let mut v1 = self.magic | (self.key >> 16);
1214        v1 = v1
1215            .overflowing_mul(20021)
1216            .0
1217            .overflowing_add(self.key.overflowing_mul(346).0)
1218            .0;
1219        v1 = (v1 + (v0 >> 16)) & 0xffff;
1220        self.key = (v1 << 16) + (v0 & 0xffff) + 1;
1221        v1 as u8
1222    }
1223}