1#![allow(clippy::erasing_op)]
2use std::cmp::Ordering;
9use std::vec;
10
11#[derive(Clone)]
12struct bbox {
13 pub ind: i32,
14 pub colors: i32,
15 pub sum: i32,
16}
17
18fn sumcompare(b1: &bbox, b2: &bbox) -> Ordering {
67 b2.sum.cmp(&b1.sum)
68}
69
70pub fn newColorMap(newcolors: i32, depth: i32) -> HashMap<i32, Tuple> {
77 let mut colormap = HashMap::new();
78 for i in 0..newcolors {
79 colormap.insert(
80 i,
81 Tuple {
82 value: 0,
83 tuple: vec![0; depth as usize],
84 },
85 );
86 }
87 colormap
88}
89
90fn newBoxVector(colors: i32, sum: i32, newcolors: i32) -> Vec<bbox> {
91 let mut result = vec![
92 bbox {
93 ind: 0,
94 colors: 0,
95 sum: 0
96 };
97 newcolors as usize
98 ];
99
100 result[0].ind = 0;
102 result[0].colors = colors;
103 result[0].sum = sum;
104
105 result
106}
107
108pub fn findBoxBoundaries(
109 colorfreqtable: &mut HashMap<i32, Tuple>,
110 depth: i32,
111 boxStart: i32,
112 boxSize: i32,
113 minval: &mut [i32],
114 maxval: &mut [i32],
115) {
116 for plane in 0..depth {
122 minval[plane as usize] = colorfreqtable.get(&(boxStart)).unwrap().tuple[plane as usize];
123 maxval[plane as usize] = minval[plane as usize];
124 }
125 for i in 1..boxSize {
126 for plane in 0..depth {
127 let v = colorfreqtable.get(&(boxStart + i)).unwrap().tuple[plane as usize];
128 minval[plane as usize] = minval[plane as usize].min(v);
129 maxval[plane as usize] = maxval[plane as usize].max(v);
130 }
131 }
132}
133
134pub fn largestByNorm(minval: &[i32], maxval: &[i32], depth: i32) -> i32 {
135 let mut largestSpreadSoFar = 0;
136 let mut largestDimension = 0;
137 for plane in 0..depth as usize {
138 let spread = maxval[plane] - minval[plane];
139 if spread > largestSpreadSoFar {
140 largestDimension = plane;
141 largestSpreadSoFar = spread;
142 }
143 }
144 largestDimension as i32
145}
146
147pub fn largestByLuminosity(minval: &[i32], maxval: &[i32], depth: i32) -> i32 {
148 let retval;
154
155 let lumin_factor = [0.2989, 0.5866, 0.1145];
156
157 if depth == 1 {
158 retval = 0;
159 } else {
160 let mut largestSpreadSoFar = 0.0;
162 let mut largestDimension = 0;
163
164 for plane in 0..3 {
165 let spread = lumin_factor[plane] * (maxval[plane] - minval[plane]) as f32;
166 if spread > largestSpreadSoFar {
167 largestDimension = plane;
168 largestSpreadSoFar = spread;
169 }
170 }
171 retval = largestDimension;
172 }
173 retval as i32
174}
175
176pub fn centerBox(
177 boxStart: i32,
178 boxSize: i32,
179 colorfreqtable: &mut HashMap<i32, Tuple>,
180 depth: i32,
181 newTuple: &mut [i32],
182) {
183 for plane in 0..depth {
184 let mut maxval = colorfreqtable.get(&(boxStart)).unwrap().tuple[plane as usize];
185 let mut minval = maxval;
186
187 for i in 1..boxSize {
188 let v = colorfreqtable.get(&(boxStart + i)).unwrap().tuple[plane as usize];
189 minval = minval.min(v);
190 maxval = maxval.max(v);
191 }
192 newTuple[plane as usize] = (minval + maxval) / 2;
193 }
194}
195
196pub fn averageColors(
197 boxStart: i32,
198 boxSize: i32,
199 colorfreqtable: &mut HashMap<i32, Tuple>,
200 depth: i32,
201 newTuple: &mut [i32],
202) {
203 for plane in 0..depth {
204 let mut sum = 0;
205
206 for i in 0..boxSize {
207 sum += colorfreqtable.get(&(boxStart + i)).unwrap().tuple[plane as usize];
208 }
209
210 newTuple[plane as usize] = sum / boxSize;
211 }
212}
213
214pub fn averagePixels(
215 boxStart: i32,
216 boxSize: i32,
217 colorfreqtable: &mut HashMap<i32, Tuple>,
218 depth: i32,
219 newTuple: &mut [i32],
220) {
221 let mut n = 0; for i in 0..boxSize {
225 n += colorfreqtable.get(&(boxStart + i)).unwrap().value;
226 }
227
228 for plane in 0..depth {
229 let mut sum = 0;
230 for i in 0..boxSize {
231 sum += colorfreqtable.get(&(boxStart + i)).unwrap().tuple[plane as usize]
232 * colorfreqtable.get(&(boxStart + i)).unwrap().value;
233 }
234 newTuple[plane as usize] = sum / n;
235 }
236}
237
238fn colormapFromBv(
239 newcolors: i32,
240 bv: &[bbox],
241 boxes: i32,
242 colorfreqtable: &mut HashMap<i32, Tuple>,
243 depth: i32,
244 methodForRep: MethodForRep,
245) -> HashMap<i32, Tuple> {
246 let mut colormap = newColorMap(newcolors, depth);
255
256 for bi in 0..boxes {
257 match methodForRep {
258 MethodForRep::CenterBox => {
259 centerBox(
260 bv[bi as usize].ind,
261 bv[bi as usize].colors,
262 colorfreqtable,
263 depth,
264 &mut colormap.get_mut(&bi).unwrap().tuple,
265 );
266 }
267 MethodForRep::AverageColors => {
268 averageColors(
269 bv[bi as usize].ind,
270 bv[bi as usize].colors,
271 colorfreqtable,
272 depth,
273 &mut colormap.get_mut(&bi).unwrap().tuple,
274 );
275 }
276 MethodForRep::Auto | MethodForRep::Pixels => {
277 averagePixels(
278 bv[bi as usize].ind,
279 bv[bi as usize].colors,
280 colorfreqtable,
281 depth,
282 &mut colormap.get_mut(&bi).unwrap().tuple,
283 );
284 }
285 }
286 }
287 colormap
288}
289
290fn splitBox(
291 bv: &mut [bbox],
292 boxesP: &mut i32,
293 bi: usize,
294 colorfreqtable: &mut HashMap<i32, Tuple>,
295 depth: i32,
296 methodForLargest: MethodForLargest,
297) -> SixelResult<()> {
298 let boxStart = bv[bi].ind;
308 let boxSize = bv[bi].colors;
309 let sm = bv[bi].sum;
310
311 let max_depth = 16;
312 let mut minval = vec![0; max_depth];
313 let mut maxval = vec![0; max_depth];
314
315 findBoxBoundaries(
318 colorfreqtable,
319 depth,
320 boxStart,
321 boxSize,
322 &mut minval,
323 &mut maxval,
324 );
325
326 let _largestDimension = match methodForLargest {
332 MethodForLargest::Auto | MethodForLargest::Norm => largestByNorm(&minval, &maxval, depth),
333 MethodForLargest::Lum => largestByLuminosity(&minval, &maxval, depth),
334 };
335
336 let mut lowersum = colorfreqtable.get(&boxStart).unwrap().value; let mut i = 1;
356 while i < boxSize - 1 && lowersum < sm / 2 {
357 lowersum += colorfreqtable.get(&(boxStart + i)).unwrap().value;
358 i += 1;
359 }
360 let medianIndex = i;
361 bv[bi].colors = medianIndex;
364 bv[bi].sum = lowersum;
365 bv[*boxesP as usize].ind = boxStart + medianIndex;
366 bv[*boxesP as usize].colors = boxSize - medianIndex;
367 bv[*boxesP as usize].sum = sm - lowersum;
368 (*boxesP) += 1;
369
370 bv[0..*boxesP as usize].sort_by(sumcompare);
371 Ok(())
372}
373
374pub fn mediancut(
375 colorfreqtable: &mut HashMap<i32, Tuple>,
376 depth: i32,
377 newcolors: i32,
378 methodForLargest: MethodForLargest,
379 methodForRep: MethodForRep,
380 colormapP: &mut HashMap<i32, Tuple>,
381) -> SixelResult<()> {
382 let mut sum = 0;
392
393 for i in 0..colorfreqtable.len() {
394 sum += colorfreqtable.get(&(i as i32)).unwrap().value;
395 }
396
397 let mut bv = newBoxVector(colorfreqtable.len() as i32, sum, newcolors);
400 let mut boxes = 1;
401 let mut multicolorBoxesExist = colorfreqtable.len() > 1;
402
403 while boxes < newcolors && multicolorBoxesExist {
405 let mut bi = 0;
407 while bi < boxes && bv[bi as usize].colors < 2 {
408 bi += 1;
409 }
410
411 if bi >= boxes {
412 multicolorBoxesExist = false;
413 } else {
414 splitBox(
415 &mut bv,
416 &mut boxes,
417 bi as usize,
418 colorfreqtable,
419 depth,
420 methodForLargest,
421 )?;
422 }
423 }
424 *colormapP = colormapFromBv(newcolors, &bv, boxes, colorfreqtable, depth, methodForRep);
425
426 Ok(())
427}
428
429pub fn computeHash(data: &[u8], i: usize, depth: i32) -> i32 {
430 let mut hash = 0;
431 for n in 0..depth {
432 hash |= (data[i + depth as usize - 1 - n as usize] as i32 >> 3) << (n * 5);
433 }
434 hash
435}
436
437#[derive(Clone)]
438pub struct Tuple {
439 pub value: i32,
440 pub tuple: Vec<i32>,
441}
442
443pub fn computeHistogram(
444 data: &[u8],
445 length: i32,
446 depth: i32,
447 qualityMode: Quality,
448) -> SixelResult<HashMap<i32, Tuple>> {
449 let (max_sample, mut step) = match qualityMode {
450 Quality::LOW => (18383, length / depth / 18383 * depth),
451 Quality::HIGH => (18383, length / depth / 18383 * depth),
452 Quality::AUTO | Quality::HIGHCOLOR | Quality::FULL => {
453 (4003079, length / depth / 4003079 * depth)
454 }
455 };
456
457 if length < max_sample * depth {
458 step = 6 * depth;
459 }
460
461 if step <= 0 {
462 step = depth;
463 }
464
465 let mut histogram = vec![0; 1 << (depth * 5)];
466
467 let mut memory = vec![0; 1 << (depth * 5)];
468 let mut it = 0;
469 let mut refe = 0;
470 let _refmap = 0;
471
472 let mut i = 0;
473 while i < length {
474 let bucket_index = computeHash(data, i as usize, 3) as usize;
475 if histogram[bucket_index] == 0 {
476 memory[refe] = bucket_index;
477 refe += 1;
478 }
479 if histogram[bucket_index] < (1 << (2 * 8)) - 1 {
480 histogram[bucket_index] += 1;
481 }
482
483 i += step;
484 }
485 let mut colorfreqtable = HashMap::new();
486
487 for i in 0..refe {
488 if histogram[memory[i]] > 0 {
489 let mut tuple: Vec<i32> = vec![0; depth as usize];
490 for n in 0..depth {
491 tuple[(depth - 1 - n) as usize] = ((memory[it] >> (n * 5) & 0x1f) << 3) as i32;
492 }
493 colorfreqtable.insert(
494 i as i32,
495 Tuple {
496 value: histogram[memory[i]],
497 tuple,
498 },
499 );
500 }
501 it += 1;
502 }
503 Ok(colorfreqtable)
504}
505
506#[allow(clippy::too_many_arguments)]
507pub fn computeColorMapFromInput(
508 data: &[u8],
509 length: i32,
510 depth: i32,
511 reqColors: i32,
512 methodForLargest: MethodForLargest,
513 methodForRep: MethodForRep,
514 qualityMode: Quality,
515 colormapP: &mut HashMap<i32, Tuple>,
516 origcolors: &mut i32,
517) -> SixelResult<()> {
518 let mut colorfreqtable = computeHistogram(data, length, depth, qualityMode)?;
539 *origcolors = colorfreqtable.len() as i32;
540
541 if colorfreqtable.len() as i32 <= reqColors {
542 for i in 0..colorfreqtable.len() as i32 {
552 colormapP.insert(i, colorfreqtable.get(&i).unwrap().clone());
553 }
554 } else {
555 mediancut(
556 &mut colorfreqtable,
557 depth,
558 reqColors,
559 methodForLargest,
560 methodForRep,
561 colormapP,
562 )?;
563 }
564 Ok(())
565}
566
567pub fn error_diffuse(
569 data: &mut [u8], pos: i32, depth: i32, error: i32, numerator: i32, denominator: i32, ) {
576 let offset = (pos * depth) as usize;
577
578 let mut c = data[offset] as i32 + error * numerator / denominator;
579 if c < 0 {
580 c = 0;
581 }
582 if c >= 1 << 8 {
583 c = (1 << 8) - 1;
584 }
585 data[offset] = c as u8;
586}
587
588pub fn diffuse_none(
589 _data: &mut [u8],
590 _width: i32,
591 _height: i32,
592 _x: i32,
593 _y: i32,
594 _depth: i32,
595 _error: i32,
596) {
597}
598
599pub fn diffuse_fs(
600 data: &mut [u8],
601 width: i32,
602 height: i32,
603 x: i32,
604 y: i32,
605 depth: i32,
606 error: i32,
607) {
608 let pos = y * width + x;
609
610 if x < width - 1 && y < height - 1 {
615 error_diffuse(data, pos + width * 0 + 1, depth, error, 7, 16);
617 error_diffuse(data, pos + width * 1 - 1, depth, error, 3, 16);
619 error_diffuse(data, pos + width * 1 + 0, depth, error, 5, 16);
621 error_diffuse(data, pos + width * 1 + 1, depth, error, 1, 16);
623 }
624}
625
626pub fn diffuse_atkinson(
627 data: &mut [u8],
628 width: i32,
629 height: i32,
630 x: i32,
631 y: i32,
632 depth: i32,
633 error: i32,
634) {
635 let pos = y * width + x;
636
637 if y < height - 2 {
643 error_diffuse(data, pos + width * 0 + 1, depth, error, 1, 8);
645 error_diffuse(data, pos + width * 0 + 2, depth, error, 1, 8);
647 error_diffuse(data, pos + width * 1 - 1, depth, error, 1, 8);
649 error_diffuse(data, pos + width * 1 + 0, depth, error, 1, 8);
651 error_diffuse(data, pos + width * 1 + 1, depth, error, 1, 8);
653 error_diffuse(data, pos + width * 2 + 0, depth, error, 1, 8);
655 }
656}
657
658pub fn diffuse_jajuni(
659 data: &mut [u8],
660 width: i32,
661 height: i32,
662 x: i32,
663 y: i32,
664 depth: i32,
665 error: i32,
666) {
667 let pos = y * width + x;
668
669 if pos < (height - 2) * width - 2 {
675 error_diffuse(data, pos + width * 0 + 1, depth, error, 7, 48);
676 error_diffuse(data, pos + width * 0 + 2, depth, error, 5, 48);
677 error_diffuse(data, pos + width * 1 - 2, depth, error, 3, 48);
678 error_diffuse(data, pos + width * 1 - 1, depth, error, 5, 48);
679 error_diffuse(data, pos + width * 1 + 0, depth, error, 7, 48);
680 error_diffuse(data, pos + width * 1 + 1, depth, error, 5, 48);
681 error_diffuse(data, pos + width * 1 + 2, depth, error, 3, 48);
682 error_diffuse(data, pos + width * 2 - 2, depth, error, 1, 48);
683 error_diffuse(data, pos + width * 2 - 1, depth, error, 3, 48);
684 error_diffuse(data, pos + width * 2 + 0, depth, error, 5, 48);
685 error_diffuse(data, pos + width * 2 + 1, depth, error, 3, 48);
686 error_diffuse(data, pos + width * 2 + 2, depth, error, 1, 48);
687 }
688}
689
690pub fn diffuse_stucki(
691 data: &mut [u8],
692 width: i32,
693 height: i32,
694 x: i32,
695 y: i32,
696 depth: i32,
697 error: i32,
698) {
699 let pos = y * width + x;
700
701 if pos < (height - 2) * width - 2 {
707 error_diffuse(data, pos + width * 0 + 1, depth, error, 1, 6);
708 error_diffuse(data, pos + width * 0 + 2, depth, error, 1, 12);
709 error_diffuse(data, pos + width * 1 - 2, depth, error, 1, 24);
710 error_diffuse(data, pos + width * 1 - 1, depth, error, 1, 12);
711 error_diffuse(data, pos + width * 1 + 0, depth, error, 1, 6);
712 error_diffuse(data, pos + width * 1 + 1, depth, error, 1, 12);
713 error_diffuse(data, pos + width * 1 + 2, depth, error, 1, 24);
714 error_diffuse(data, pos + width * 2 - 2, depth, error, 1, 48);
715 error_diffuse(data, pos + width * 2 - 1, depth, error, 1, 24);
716 error_diffuse(data, pos + width * 2 + 0, depth, error, 1, 12);
717 error_diffuse(data, pos + width * 2 + 1, depth, error, 1, 24);
718 error_diffuse(data, pos + width * 2 + 2, depth, error, 1, 48);
719 }
720}
721
722pub fn diffuse_burkes(
723 data: &mut [u8],
724 width: i32,
725 height: i32,
726 x: i32,
727 y: i32,
728 depth: i32,
729 error: i32,
730) {
731 let pos = y * width + x;
732
733 if pos < (height - 1) * width - 2 {
738 error_diffuse(data, pos + width * 0 + 1, depth, error, 1, 4);
739 error_diffuse(data, pos + width * 0 + 2, depth, error, 1, 8);
740 error_diffuse(data, pos + width * 1 - 2, depth, error, 1, 16);
741 error_diffuse(data, pos + width * 1 - 1, depth, error, 1, 8);
742 error_diffuse(data, pos + width * 1 + 0, depth, error, 1, 4);
743 error_diffuse(data, pos + width * 1 + 1, depth, error, 1, 8);
744 error_diffuse(data, pos + width * 1 + 2, depth, error, 1, 16);
745 }
746}
747
748pub fn mask_a(x: i32, y: i32, c: i32) -> f32 {
749 ((((x + c * 67) + y * 236) * 119) & 255) as f32 / 128.0 - 1.0
750}
751
752pub fn mask_x(x: i32, y: i32, c: i32) -> f32 {
753 ((((x + c * 29) ^ (y * 149)) * 1234) & 511) as f32 / 256.0 - 1.0
754}
755
756use std::collections::HashMap;
757
758use crate::{
759 pixelformat::sixel_helper_compute_depth, MethodForLargest, PixelFormat, Quality, SixelResult,
760};
761use crate::{DiffusionMethod, MethodForRep, SixelError};
762
763pub fn lookup_normal(
765 pixel: &[u8],
766 depth: i32,
767 palette: &[u8],
768 reqcolor: i32,
769 _cachetable: &mut [u16],
770 complexion: i32,
771) -> i32 {
772 let mut result = -1;
773 let mut diff = i32::MAX;
774
775 for i in 0..reqcolor {
778 let mut distant = 0;
779 let mut r = pixel[0] as i32 - palette[(i * depth + 0) as usize] as i32;
780 distant += r * r * complexion;
781 for n in 1..depth {
782 r = pixel[n as usize] as i32 - palette[(i * depth + n) as usize] as i32;
783 distant += r * r;
784 }
785 if distant < diff {
786 diff = distant;
787 result = i;
788 }
789 }
790
791 result
792}
793
794pub fn lookup_fast(
796 pixel: &[u8],
797 _depth: i32,
798 palette: &[u8],
799 reqcolor: i32,
800 cachetable: &mut [u16],
801 complexion: i32,
802) -> i32 {
803 let mut result: i32 = -1;
804 let mut diff = i32::MAX;
805 let hash = computeHash(pixel, 0, 3);
806
807 let cache = cachetable[hash as usize];
808 if cache != 0 {
809 return cache as i32 - 1;
811 }
812 for i in 0..reqcolor {
814 let i = i as usize;
823 let distant = (pixel[0] as i32 - palette[i * 3 + 0] as i32)
824 * (pixel[0] as i32 - palette[i * 3 + 0] as i32)
825 * complexion
826 + (pixel[1] as i32 - palette[i * 3 + 1] as i32)
827 * (pixel[1] as i32 - palette[i * 3 + 1] as i32)
828 + (pixel[2] as i32 - palette[i * 3 + 2] as i32)
829 * (pixel[2] as i32 - palette[i * 3 + 2] as i32);
830 if distant < diff {
832 diff = distant;
833 result = i as i32;
834 }
835 }
836 cachetable[hash as usize] = (result + 1) as u16;
837
838 result
839}
840
841pub fn lookup_mono_darkbg(
842 pixel: &[u8],
843 depth: i32,
844 _palette: &[u8],
845 reqcolor: i32,
846 _cachetable: &mut [u16],
847 _complexion: i32,
848) -> i32 {
849 let mut distant = 0;
850 for n in 0..depth {
851 distant += pixel[n as usize] as i32;
852 }
853 if distant >= 128 * reqcolor {
854 1
855 } else {
856 0
857 }
858}
859
860pub fn lookup_mono_lightbg(
861 pixel: &[u8],
862 depth: i32,
863 _palette: &[u8],
864 reqcolor: i32,
865 _cachetable: &mut [u16],
866 _complexion: i32,
867) -> i32 {
868 let mut distant = 0;
869 for n in 0..depth {
870 distant += pixel[n as usize] as i32;
871 }
872 if distant < 128 * reqcolor {
873 1
874 } else {
875 0
876 }
877}
878
879#[allow(clippy::too_many_arguments)]
881pub fn sixel_quant_make_palette(
882 data: &[u8],
883 length: i32,
884 pixelformat: PixelFormat,
885 reqcolors: i32,
886 ncolors: &mut i32,
887 origcolors: &mut i32,
888 methodForLargest: MethodForLargest,
889 methodForRep: MethodForRep,
890 qualityMode: Quality,
891) -> SixelResult<Vec<u8>> {
892 let result_depth = sixel_helper_compute_depth(pixelformat);
893 let depth = result_depth as usize;
899 let mut colormap = HashMap::new();
900 let _ = computeColorMapFromInput(
901 data,
902 length,
903 depth as i32,
904 reqcolors,
905 methodForLargest,
906 methodForRep,
907 qualityMode,
908 &mut colormap,
909 origcolors,
910 );
911 *ncolors = colormap.len() as i32;
912 let mut result = vec![0; colormap.len() * depth as usize];
913 for i in 0..colormap.len() {
914 for n in 0..depth {
915 result[i * depth + n] = colormap.get(&(i as i32)).unwrap().tuple[n] as u8;
916 }
917 }
918 Ok(result)
919}
920
921#[allow(clippy::too_many_arguments)]
923pub fn sixel_quant_apply_palette(
924 result: &mut [u8],
925 data: &mut [u8],
926 width: i32,
927 height: i32,
928 depth: i32,
929 palette: &mut Vec<u8>,
930 reqcolor: i32,
931 methodForDiffuse: DiffusionMethod,
932 foptimize: bool,
933 foptimize_palette: bool,
934 complexion: i32,
935 cachetable: Option<&mut [u16]>,
936) -> SixelResult<i32> {
937 let mut ncolors: i32;
938 if reqcolor < 1 {
940 return Err(Box::new(SixelError::BadArgument));
946 }
947
948 let mut f_mask = false;
949
950 let f_diffuse = if depth != 3 {
951 diffuse_none
952 } else {
953 match methodForDiffuse {
954 DiffusionMethod::Auto | DiffusionMethod::None => diffuse_none,
955 DiffusionMethod::Atkinson => diffuse_atkinson,
956 DiffusionMethod::FS => diffuse_fs,
957 DiffusionMethod::JaJuNi => diffuse_jajuni,
958 DiffusionMethod::Stucki => diffuse_stucki,
959 DiffusionMethod::Burkes => diffuse_burkes,
960 DiffusionMethod::ADither => {
961 f_mask = true;
962 diffuse_none
963 }
964 DiffusionMethod::XDither => {
965 f_mask = true;
966 diffuse_none
967 }
968 }
969 };
970 type LookupFunc = fn(&[u8], i32, &[u8], i32, &mut [u16], i32) -> i32;
971 let mut f_lookup: Option<LookupFunc> = None;
972 if reqcolor == 2 {
973 let mut sum1 = 0;
974 let mut sum2 = 0;
975 for n in 0..depth {
976 sum1 += palette[n as usize] as i32;
977 }
978 for n in depth..(depth + depth) {
979 sum2 += palette[n as usize] as i32;
980 }
981 if sum1 == 0 && sum2 == 255 * 3 {
982 f_lookup = Some(lookup_mono_darkbg);
983 } else if sum1 == 255 * 3 && sum2 == 0 {
984 f_lookup = Some(lookup_mono_lightbg);
985 }
986 }
987 if f_lookup.is_none() {
988 if foptimize && depth == 3 {
989 f_lookup = Some(lookup_fast);
990 } else {
991 f_lookup = Some(lookup_normal);
992 }
993 }
994
995 let mut cc = vec![0u16, 1 << (depth * 5)];
996 let indextable = match cachetable {
997 Some(table) => table,
998 None => &mut cc,
999 };
1000
1001 if foptimize_palette {
1002 ncolors = 0;
1003 let mut new_palette = vec![0; crate::SIXEL_PALETTE_MAX * depth as usize];
1004 let mut migration_map = vec![0; crate::SIXEL_PALETTE_MAX];
1005
1006 if f_mask {
1007 for y in 0..height {
1008 for x in 0..width {
1009 let mut copy: Vec<u8> = Vec::new();
1010
1011 let pos = y * width + x;
1012 for d in 0..depth {
1013 let mut val = data[(pos * depth + d) as usize] as i32;
1014 if matches!(methodForDiffuse, DiffusionMethod::ADither) {
1015 val += (mask_a(x, y, d) * 32.0) as i32;
1016 } else {
1017 val += (mask_x(x, y, d) * 32.0) as i32;
1018 }
1019 copy.push(val.clamp(0, 255) as u8);
1020 }
1021 let color_index =
1023 f_lookup.unwrap()(©, depth, palette, reqcolor, indextable, complexion)
1024 as usize;
1025 if migration_map[color_index] == 0 {
1026 result[pos as usize] = ncolors as u8;
1027 for n in 0..depth {
1028 new_palette[(ncolors * depth + n) as usize] =
1029 palette[color_index * depth as usize + n as usize];
1030 }
1031 ncolors += 1;
1032 migration_map[color_index] = ncolors;
1033 } else {
1034 result[pos as usize] = migration_map[color_index] as u8 - 1;
1035 }
1036 }
1037 }
1038 *palette = new_palette;
1039 } else {
1040 for y in 0..height {
1041 for x in 0..width {
1042 let pos = y * width + x;
1043 let color_index = f_lookup.unwrap()(
1044 &data[(pos * depth) as usize..],
1045 depth,
1046 palette,
1047 reqcolor,
1048 indextable,
1049 complexion,
1050 ) as usize;
1051 if migration_map[color_index] == 0 {
1052 result[pos as usize] = ncolors as u8;
1053 for n in 0..depth {
1054 new_palette[(ncolors * depth + n) as usize] =
1055 palette[color_index * depth as usize + n as usize];
1056 }
1057 ncolors += 1;
1058 migration_map[color_index] = ncolors;
1059 } else {
1060 result[pos as usize] = migration_map[color_index] as u8 - 1;
1061 }
1062 for n in 0..depth {
1063 let offset = data[(pos * depth + n) as usize] as i32
1064 - palette[color_index * depth as usize + n as usize] as i32;
1065 f_diffuse(&mut data[n as usize..], width, height, x, y, depth, offset);
1066 }
1067 }
1068 }
1069 *palette = new_palette;
1070 }
1071 } else {
1072 if f_mask {
1073 for y in 0..height {
1074 for x in 0..width {
1075 let mut copy = Vec::new();
1076 let pos = y * width + x;
1077 for d in 0..depth {
1078 let mut val = data[(pos * depth + d) as usize] as i32;
1079 if matches!(methodForDiffuse, DiffusionMethod::ADither) {
1080 val += (mask_a(x, y, d) * 32.0) as i32;
1081 } else {
1082 val += (mask_x(x, y, d) * 32.0) as i32;
1083 }
1084
1085 copy.push(val.clamp(0, 255) as u8);
1086 }
1087 result[pos as usize] = f_lookup.unwrap()(
1088 &mut copy, depth, palette, reqcolor, indextable, complexion,
1089 ) as u8;
1090 }
1091 }
1092 } else {
1093 for y in 0..height {
1094 for x in 0..width {
1095 let pos = y * width + x;
1096 let color_index = f_lookup.unwrap()(
1097 &mut data[(pos * depth) as usize..],
1098 depth,
1099 palette,
1100 reqcolor,
1101 indextable,
1102 complexion,
1103 ) as usize;
1104 result[pos as usize] = color_index as u8;
1105 for n in 0..depth {
1106 let offset = data[(pos * depth + n) as usize] as i32
1107 - palette[color_index * depth as usize + n as usize] as i32;
1108 f_diffuse(&mut data[n as usize..], width, height, x, y, depth, offset);
1109 }
1110 }
1111 }
1112 }
1113 ncolors = reqcolor;
1114 }
1115
1116 Ok(ncolors)
1117}
1118
1119