• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

saitoha / libsixel / 19765269522

28 Nov 2025 01:30PM UTC coverage: 39.983% (-1.6%) from 41.616%
19765269522

push

github

web-flow
Merge pull request #214 from saitoha/codex/add-logging-to-resize-processing

Limit scale logging and add timeline window controls

9788 of 35562 branches covered (27.52%)

9 of 63 new or added lines in 1 file covered. (14.29%)

281 existing lines in 19 files now uncovered.

12991 of 32491 relevant lines covered (39.98%)

619662.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/dither-varcoeff-float32.c
1
/*
2
 * SPDX-License-Identifier: MIT
3
 *
4
 * Copyright (c) 2025 libsixel developers. See `AUTHORS`.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
 * SOFTWARE.
23
 */
24

25
/*
26
 * Adaptive diffusion backend operating on RGBFLOAT32 buffers.  The worker
27
 * mirrors the 8bit implementation but keeps intermediate values in float so
28
 * rounding happens only at palette lookups.
29
 */
30

31
#include "config.h"
32

33
#include <stdlib.h>
34
#include <string.h>
35

36
#if HAVE_MATH_H
37
# include <math.h>
38
#endif  /* HAVE_MATH_H */
39

40
#include "dither-varcoeff-float32.h"
41
#include "dither-common-pipeline.h"
42
#include "lookup-common.h"
43
#include "pixelformat.h"
44

45
static void
46
sixel_dither_scanline_params(int serpentine,
×
47
                             int index,
48
                             int limit,
49
                             int *start,
50
                             int *end,
51
                             int *step,
52
                             int *direction)
53
{
54
    if (serpentine && (index & 1)) {
×
55
        *start = limit - 1;
×
56
        *end = -1;
×
57
        *step = -1;
×
58
        *direction = -1;
×
59
    } else {
60
        *start = 0;
×
61
        *end = limit;
×
62
        *step = 1;
×
63
        *direction = 1;
×
64
    }
65
}
×
66

67
static const int (*
68
lso2_table(void))[7]
×
69
{
70
#include "lso2.h"
UNCOV
71
    return var_coefs;
×
72
}
73

74
typedef void (*diffuse_varerr_mode_float)(float *data,
75
                                          int width,
76
                                          int height,
77
                                          int x,
78
                                          int y,
79
                                          int depth,
80
                                          float error,
81
                                          int index,
82
                                          int direction,
83
                                          int pixelformat,
84
                                          int channel);
85

86
typedef void (*diffuse_varerr_carry_mode_float)(float *carry_curr,
87
                                                 float *carry_next,
88
                                                 float *carry_far,
89
                                                 int width,
90
                                                 int height,
91
                                                 int depth,
92
                                                 int x,
93
                                                 int y,
94
                                                 float error,
95
                                                 int index,
96
                                                 int direction,
97
                                                 int channel);
98

99
static int
100
sixel_varcoeff_safe_denom(int value)
×
101
{
102
    if (value == 0) {
×
103
        return 1;
×
104
    }
105
    return value;
×
106
}
107

108
static float
109
diffuse_varerr_term_float(float error, int weight, int denom)
×
110
{
111
    float factor;
112

113
    factor = (float)weight / (float)denom;
×
114
    return error * factor;
×
115
}
116

117
static void
118
diffuse_varerr_apply_direct_float(float *target,
×
119
                                  int depth,
120
                                  size_t offset,
121
                                  float delta,
122
                                  int pixelformat,
123
                                  int channel)
124
{
125
    size_t index;
126

127
    index = offset * (size_t)depth;
×
128
    target[index] += delta;
×
129
    target[index] = sixel_pixelformat_float_channel_clamp(pixelformat,
×
130
                                                          channel,
131
                                                          target[index]);
×
132
}
×
133

134
static void
135
diffuse_lso2_float(float *data,
×
136
                    int width,
137
                    int height,
138
                    int x,
139
                    int y,
140
                    int depth,
141
                    float error,
142
                    int index,
143
                    int direction,
144
                    int pixelformat,
145
                    int channel)
146
{
147
    const int (*table)[7];
148
    const int *entry;
149
    int denom;
150
    float term_r;
151
    float term_r2;
152
    float term_dl;
153
    float term_d;
154
    float term_dr;
155
    float term_d2;
156
    size_t offset;
157

158
    if (error == 0.0f) {
×
159
        return;
×
160
    }
161
    if (index < 0) {
×
162
        index = 0;
×
163
    }
164
    if (index > 255) {
×
165
        index = 255;
×
166
    }
167

168
    if (pixelformat == SIXEL_PIXELFORMAT_OKLABFLOAT32 ||
×
169
            pixelformat == SIXEL_PIXELFORMAT_CIELABFLOAT32 ||
×
170
            pixelformat == SIXEL_PIXELFORMAT_DIN99DFLOAT32) {
171
        if (channel > 0) {  /* ab */
×
172
            error *= 0.10;
×
173
        }
174
    }
175
    table = lso2_table();
×
176
    entry = table[index];
×
177
    denom = sixel_varcoeff_safe_denom(entry[6]);
×
178

179
    term_r = diffuse_varerr_term_float(error, entry[0], denom);
×
180
    term_r2 = diffuse_varerr_term_float(error, entry[1], denom);
×
181
    term_dl = diffuse_varerr_term_float(error, entry[2], denom);
×
182
    term_d = diffuse_varerr_term_float(error, entry[3], denom);
×
183
    term_dr = diffuse_varerr_term_float(error, entry[4], denom);
×
184
    term_d2 = diffuse_varerr_term_float(error, entry[5], denom);
×
185

186
    if (direction >= 0) {
×
187
        if (x + 1 < width) {
×
188
            offset = (size_t)y * (size_t)width + (size_t)(x + 1);
×
189
            diffuse_varerr_apply_direct_float(data,
×
190
                                              depth,
191
                                              offset,
192
                                              term_r,
193
                                              pixelformat,
194
                                              channel);
195
        }
196
        if (x + 2 < width) {
×
197
            offset = (size_t)y * (size_t)width + (size_t)(x + 2);
×
198
            diffuse_varerr_apply_direct_float(data,
×
199
                                              depth,
200
                                              offset,
201
                                              term_r2,
202
                                              pixelformat,
203
                                              channel);
204
        }
205
        if (y + 1 < height && x - 1 >= 0) {
×
206
            offset = (size_t)(y + 1) * (size_t)width;
×
207
            offset += (size_t)(x - 1);
×
208
            diffuse_varerr_apply_direct_float(data,
×
209
                                              depth,
210
                                              offset,
211
                                              term_dl,
212
                                              pixelformat,
213
                                              channel);
214
        }
215
        if (y + 1 < height) {
×
216
            offset = (size_t)(y + 1) * (size_t)width + (size_t)x;
×
217
            diffuse_varerr_apply_direct_float(data,
×
218
                                              depth,
219
                                              offset,
220
                                              term_d,
221
                                              pixelformat,
222
                                              channel);
223
        }
224
        if (y + 1 < height && x + 1 < width) {
×
225
            offset = (size_t)(y + 1) * (size_t)width;
×
226
            offset += (size_t)(x + 1);
×
227
            diffuse_varerr_apply_direct_float(data,
×
228
                                              depth,
229
                                              offset,
230
                                              term_dr,
231
                                              pixelformat,
232
                                              channel);
233
        }
234
        if (y + 2 < height) {
×
235
            offset = (size_t)(y + 2) * (size_t)width + (size_t)x;
×
236
            diffuse_varerr_apply_direct_float(data,
×
237
                                              depth,
238
                                              offset,
239
                                              term_d2,
240
                                              pixelformat,
241
                                              channel);
242
        }
243
    } else {
244
        if (x - 1 >= 0) {
×
245
            offset = (size_t)y * (size_t)width + (size_t)(x - 1);
×
246
            diffuse_varerr_apply_direct_float(data,
×
247
                                              depth,
248
                                              offset,
249
                                              term_r,
250
                                              pixelformat,
251
                                              channel);
252
        }
253
        if (x - 2 >= 0) {
×
254
            offset = (size_t)y * (size_t)width + (size_t)(x - 2);
×
255
            diffuse_varerr_apply_direct_float(data,
×
256
                                              depth,
257
                                              offset,
258
                                              term_r2,
259
                                              pixelformat,
260
                                              channel);
261
        }
262
        if (y + 1 < height && x + 1 < width) {
×
263
            offset = (size_t)(y + 1) * (size_t)width;
×
264
            offset += (size_t)(x + 1);
×
265
            diffuse_varerr_apply_direct_float(data,
×
266
                                              depth,
267
                                              offset,
268
                                              term_dl,
269
                                              pixelformat,
270
                                              channel);
271
        }
272
        if (y + 1 < height) {
×
273
            offset = (size_t)(y + 1) * (size_t)width + (size_t)x;
×
274
            diffuse_varerr_apply_direct_float(data,
×
275
                                              depth,
276
                                              offset,
277
                                              term_d,
278
                                              pixelformat,
279
                                              channel);
280
        }
281
        if (y + 1 < height && x - 1 >= 0) {
×
282
            offset = (size_t)(y + 1) * (size_t)width;
×
283
            offset += (size_t)(x - 1);
×
284
            diffuse_varerr_apply_direct_float(data,
×
285
                                              depth,
286
                                              offset,
287
                                              term_dr,
288
                                              pixelformat,
289
                                              channel);
290
        }
291
        if (y + 2 < height) {
×
292
            offset = (size_t)(y + 2) * (size_t)width + (size_t)x;
×
293
            diffuse_varerr_apply_direct_float(data,
×
294
                                              depth,
295
                                              offset,
296
                                              term_d2,
297
                                              pixelformat,
298
                                              channel);
299
        }
300
    }
301
}
302

303
static void
304
diffuse_lso2_carry_float(float *carry_curr,
×
305
                          float *carry_next,
306
                          float *carry_far,
307
                          int width,
308
                          int height,
309
                          int depth,
310
                          int x,
311
                          int y,
312
                          float error,
313
                          int index,
314
                          int direction,
315
                          int channel)
316
{
317
    const int (*table)[7];
318
    const int *entry;
319
    int denom;
320
    float term_r;
321
    float term_r2;
322
    float term_dl;
323
    float term_d;
324
    float term_dr;
325
    float term_d2;
326
    size_t base;
327

328
    if (error == 0.0f) {
×
329
        return;
×
330
    }
331
    if (index < 0) {
×
332
        index = 0;
×
333
    }
334
    if (index > 255) {
×
335
        index = 255;
×
336
    }
337

338
    table = lso2_table();
×
339
    entry = table[index];
×
340
    denom = sixel_varcoeff_safe_denom(entry[6]);
×
341

342
    term_r = diffuse_varerr_term_float(error, entry[0], denom);
×
343
    term_r2 = diffuse_varerr_term_float(error, entry[1], denom);
×
344
    term_dl = diffuse_varerr_term_float(error, entry[2], denom);
×
345
    term_d = diffuse_varerr_term_float(error, entry[3], denom);
×
346
    term_dr = diffuse_varerr_term_float(error, entry[4], denom);
×
347
    term_d2 = error - term_r - term_r2 - term_dl - term_d - term_dr;
×
348

349
    if (direction >= 0) {
×
350
        if (x + 1 < width) {
×
351
            base = ((size_t)(x + 1) * (size_t)depth)
×
352
                 + (size_t)channel;
×
353
            carry_curr[base] += term_r;
×
354
        }
355
        if (x + 2 < width) {
×
356
            base = ((size_t)(x + 2) * (size_t)depth)
×
357
                 + (size_t)channel;
×
358
            carry_curr[base] += term_r2;
×
359
        }
360
        if (y + 1 < height && x - 1 >= 0) {
×
361
            base = ((size_t)(x - 1) * (size_t)depth)
×
362
                 + (size_t)channel;
×
363
            carry_next[base] += term_dl;
×
364
        }
365
        if (y + 1 < height) {
×
366
            base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
367
            carry_next[base] += term_d;
×
368
        }
369
        if (y + 1 < height && x + 1 < width) {
×
370
            base = ((size_t)(x + 1) * (size_t)depth)
×
371
                 + (size_t)channel;
×
372
            carry_next[base] += term_dr;
×
373
        }
374
        if (y + 2 < height) {
×
375
            base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
376
            carry_far[base] += term_d2;
×
377
        }
378
    } else {
379
        if (x - 1 >= 0) {
×
380
            base = ((size_t)(x - 1) * (size_t)depth)
×
381
                 + (size_t)channel;
×
382
            carry_curr[base] += term_r;
×
383
        }
384
        if (x - 2 >= 0) {
×
385
            base = ((size_t)(x - 2) * (size_t)depth)
×
386
                 + (size_t)channel;
×
387
            carry_curr[base] += term_r2;
×
388
        }
389
        if (y + 1 < height && x + 1 < width) {
×
390
            base = ((size_t)(x + 1) * (size_t)depth)
×
391
                 + (size_t)channel;
×
392
            carry_next[base] += term_dl;
×
393
        }
394
        if (y + 1 < height) {
×
395
            base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
396
            carry_next[base] += term_d;
×
397
        }
398
        if (y + 1 < height && x - 1 >= 0) {
×
399
            base = ((size_t)(x - 1) * (size_t)depth)
×
400
                 + (size_t)channel;
×
401
            carry_next[base] += term_dr;
×
402
        }
403
        if (y + 2 < height) {
×
404
            base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
405
            carry_far[base] += term_d2;
×
406
        }
407
    }
408
}
409

410
SIXELSTATUS
411
sixel_dither_apply_varcoeff_float32(sixel_dither_t *dither,
×
412
                                    sixel_dither_context_t *context)
UNCOV
413
{
×
414
#if _MSC_VER
415
    enum { max_channels = 4 };
416
#else
417
    const int max_channels = 4;
×
418
#endif
419
    SIXELSTATUS status;
420
    float *data;
421
    unsigned char *palette;
422
    unsigned char *new_palette;
423
    float *source_pixel;
UNCOV
424
    float corrected[max_channels];
×
425
    float quantized_float;
UNCOV
426
    unsigned char quantized[max_channels];
×
427
    float *carry_curr;
428
    float *carry_next;
429
    float *carry_far;
430
    float palette_value_float;
431
    unsigned char palette_value;
432
    float error;
433
    int serpentine;
434
    int use_carry;
435
    size_t carry_len;
436
    int method_for_diffuse;
437
    int method_for_carry;
438
    int method_for_scan;
439
    sixel_lut_t *fast_lut;
440
    int use_fast_lut;
441
    diffuse_varerr_mode_float varerr_diffuse;
442
    diffuse_varerr_carry_mode_float varerr_diffuse_carry;
443
    int optimize_palette;
444
    int y;
445
    int absolute_y;
446
    int start;
447
    int end;
448
    int step;
449
    int direction;
450
    int x;
451
    int pos;
452
    size_t base;
453
    size_t carry_base;
454
    int depth;
455
    int reqcolor;
456
    int n;
457
    int color_index;
458
    int output_index;
459
    int diff;
460
    int table_index;
461
    unsigned short *indextable;
462
    unsigned short *migration_map;
463
    int *ncolors;
464
    int (*lookup)(const unsigned char *,
465
                  int,
466
                  const unsigned char *,
467
                  int,
468
                  unsigned short *,
469
                  int);
470
    float *palette_float;
471
    float *new_palette_float;
472
    int float_depth;
473
    int float_index;
UNCOV
474
    float lookup_pixel_float[max_channels];
×
475
    unsigned char const *lookup_pixel;
476
    int lookup_wants_float;
477
    int use_palette_float_lookup;
478
    int need_float_pixel;
479
    int have_palette_float;
480
    int have_new_palette_float;
481

482
    if (dither == NULL || context == NULL) {
×
483
        return SIXEL_BAD_ARGUMENT;
×
484
    }
485

486
    status = SIXEL_BAD_ARGUMENT;
×
487
    data = context->pixels_float;
×
488
    palette = context->palette;
×
489
    new_palette = context->new_palette;
×
490
    indextable = context->indextable;
×
491
    migration_map = context->migration_map;
×
492
    ncolors = context->ncolors;
×
493
    depth = context->depth;
×
494
    reqcolor = context->reqcolor;
×
495
    lookup = context->lookup;
×
496
    fast_lut = context->lut;
×
497
    use_fast_lut = (fast_lut != NULL);
×
498
    optimize_palette = context->optimize_palette;
×
499
    method_for_diffuse = context->method_for_diffuse;
×
500
    method_for_carry = context->method_for_carry;
×
501
    method_for_scan = context->method_for_scan;
×
502
    palette_float = context->palette_float;
×
503
    new_palette_float = context->new_palette_float;
×
504
    float_depth = context->float_depth;
×
505
    /*
506
     * Track float palette availability separately for the original palette
507
     * and the palette-optimization buffer so later loops can skip
508
     * byte-to-float round-trips when computing the quantization error.
509
     */
510
    if (palette_float != NULL && float_depth >= depth) {
×
511
        have_palette_float = 1;
×
512
    } else {
513
        have_palette_float = 0;
×
514
    }
515
    if (new_palette_float != NULL && float_depth >= depth) {
×
516
        have_new_palette_float = 1;
×
517
    } else {
518
        have_new_palette_float = 0;
×
519
    }
520

521
    if (data == NULL || palette == NULL || context->result == NULL) {
×
522
        return SIXEL_BAD_ARGUMENT;
×
523
    }
524
    if (lookup == NULL) {
×
525
        return SIXEL_BAD_ARGUMENT;
×
526
    }
527
    if (optimize_palette) {
×
528
        if (new_palette == NULL || migration_map == NULL || ncolors == NULL) {
×
529
            return SIXEL_BAD_ARGUMENT;
×
530
        }
531
    } else if (ncolors == NULL) {
×
532
        return SIXEL_BAD_ARGUMENT;
×
533
    }
534

535
    if (depth <= 0 || depth > max_channels) {
×
536
        return SIXEL_BAD_ARGUMENT;
×
537
    }
538

539
    switch (method_for_diffuse) {
×
540
    case SIXEL_DIFFUSE_LSO2:
×
541
    default:
542
        varerr_diffuse = diffuse_lso2_float;
×
543
        varerr_diffuse_carry = diffuse_lso2_carry_float;
×
544
        break;
×
545
    }
546

547
    use_carry = (method_for_carry == SIXEL_CARRY_ENABLE);
×
548
    carry_curr = NULL;
×
549
    carry_next = NULL;
×
550
    carry_far = NULL;
×
551
    carry_len = 0;
×
552

553
    if (use_carry) {
×
554
        carry_len = (size_t)context->width * (size_t)depth;
×
555
        carry_curr = (float *)calloc(carry_len, sizeof(float));
×
556
        carry_next = (float *)calloc(carry_len, sizeof(float));
×
557
        carry_far = (float *)calloc(carry_len, sizeof(float));
×
558
        if (carry_curr == NULL || carry_next == NULL || carry_far == NULL) {
×
559
            goto end;
×
560
        }
561
    }
562

563
    serpentine = (method_for_scan == SIXEL_SCAN_SERPENTINE);
×
564
    lookup_wants_float = (context->lookup_source_is_float != 0);
×
565
    use_palette_float_lookup = 0;
×
566
    if (context->prefer_palette_float_lookup != 0
×
567
            && palette_float != NULL
×
568
            && float_depth >= depth) {
×
569
        use_palette_float_lookup = 1;
×
570
    }
571
    need_float_pixel = lookup_wants_float || use_palette_float_lookup;
×
572
    if (optimize_palette) {
×
573
        *ncolors = 0;
×
574
        memset(new_palette, 0x00,
×
UNCOV
575
               (size_t)SIXEL_PALETTE_MAX * (size_t)depth);
×
576
        if (new_palette_float != NULL && float_depth > 0) {
×
577
            memset(new_palette_float, 0x00,
×
578
                   (size_t)SIXEL_PALETTE_MAX
UNCOV
579
                       * (size_t)float_depth * sizeof(float));
×
580
        }
581
        memset(migration_map, 0x00,
×
582
               sizeof(unsigned short) * (size_t)SIXEL_PALETTE_MAX);
583
    }
584

585
    for (y = 0; y < context->height; ++y) {
×
586
        absolute_y = context->band_origin + y;
×
587
        sixel_dither_scanline_params(serpentine,
×
588
                                     absolute_y,
589
                                     context->width,
590
                                     &start,
591
                                     &end,
592
                                     &step,
593
                                     &direction);
594
        for (x = start; x != end; x += step) {
×
595
            pos = y * context->width + x;
×
596
            base = (size_t)pos * (size_t)depth;
×
597
            carry_base = (size_t)x * (size_t)depth;
×
598
            if (use_carry) {
×
599
                for (n = 0; n < depth; ++n) {
×
600
                    float accum;
601

602
                    accum = data[base + (size_t)n]
×
603
                           + carry_curr[carry_base + (size_t)n];
×
604
                    carry_curr[carry_base + (size_t)n] = 0.0f;
×
605
                    accum = sixel_pixelformat_float_channel_clamp(
×
606
                        context->pixelformat,
607
                        n,
608
                        accum);
609
                    corrected[n] = accum;
×
610
                }
611
                source_pixel = corrected;
×
612
            } else {
613
                source_pixel = data + base;
×
614
            }
615

616
            for (n = 0; n < depth; ++n) {
×
617
                quantized_float = source_pixel[n];
×
618
                quantized_float = sixel_pixelformat_float_channel_clamp(
×
619
                    context->pixelformat,
620
                    n,
621
                    quantized_float);
622
                if (source_pixel == data + base) {
×
623
                    source_pixel[n] = quantized_float;
×
624
                }
625
                if (need_float_pixel) {
×
626
                    lookup_pixel_float[n] = quantized_float;
×
627
                }
628
                if (!lookup_wants_float && !use_palette_float_lookup) {
×
629
                    quantized[n] = sixel_pixelformat_float_channel_to_byte(
×
630
                        context->pixelformat,
631
                        n,
632
                        quantized_float);
633
                }
634
            }
635
            if (lookup_wants_float) {
×
636
                lookup_pixel = (unsigned char const *)(void const *)
×
637
                    lookup_pixel_float;
638
                if (use_fast_lut) {
×
639
                    color_index = sixel_lut_map_pixel(fast_lut,
×
640
                                                     lookup_pixel);
641
                } else {
642
                    color_index = lookup(lookup_pixel,
×
643
                                         depth,
644
                                         palette,
645
                                         reqcolor,
646
                                         indextable,
647
                                         context->complexion);
648
                }
649
            } else if (use_palette_float_lookup) {
×
650
                color_index = sixel_dither_lookup_palette_float32(
×
651
                    lookup_pixel_float,
652
                    depth,
653
                    palette_float,
654
                    reqcolor,
655
                    context->complexion);
656
            } else {
657
                lookup_pixel = quantized;
×
658
                if (use_fast_lut) {
×
659
                    color_index = sixel_lut_map_pixel(fast_lut,
×
660
                                                     lookup_pixel);
661
                } else {
662
                    color_index = lookup(lookup_pixel,
×
663
                                         depth,
664
                                         palette,
665
                                         reqcolor,
666
                                         indextable,
667
                                         context->complexion);
668
                }
669
            }
670

671
            if (optimize_palette) {
×
672
                if (migration_map[color_index] == 0) {
×
673
                    output_index = *ncolors;
×
674
                    for (n = 0; n < depth; ++n) {
×
675
                        new_palette[output_index * depth + n]
×
676
                            = palette[color_index * depth + n];
×
677
                    }
678
                    if (palette_float != NULL
×
679
                            && new_palette_float != NULL
×
680
                            && float_depth > 0) {
×
681
                        for (float_index = 0;
×
682
                                float_index < float_depth;
×
683
                                ++float_index) {
×
684
                            new_palette_float[output_index * float_depth
×
685
                                              + float_index]
×
686
                                = palette_float[color_index * float_depth
×
687
                                                + float_index];
×
688
                        }
689
                    }
690
                    ++*ncolors;
×
691
                    migration_map[color_index] = *ncolors;
×
692
                } else {
693
                    output_index = migration_map[color_index] - 1;
×
694
                }
695
                if (absolute_y >= context->output_start) {
×
696
                    context->result[pos] = output_index;
×
697
                }
698
            } else {
699
                output_index = color_index;
×
700
                if (absolute_y >= context->output_start) {
×
701
                    context->result[pos] = output_index;
×
702
                }
703
            }
704

705
            for (n = 0; n < depth; ++n) {
×
706
                if (optimize_palette) {
×
707
                    if (have_new_palette_float) {
×
708
                        palette_value_float =
×
709
                            new_palette_float[output_index * float_depth
×
710
                                              + n];
×
711
                    } else {
712
                        palette_value =
×
713
                            new_palette[output_index * depth + n];
×
714
                        palette_value_float
715
                            = sixel_pixelformat_byte_to_float(
×
716
                                  context->pixelformat,
717
                                  n,
718
                                  palette_value);
719
                    }
720
                } else {
721
                    if (have_palette_float) {
×
722
                        palette_value_float =
×
723
                            palette_float[color_index * float_depth + n];
×
724
                    } else {
725
                        palette_value =
×
726
                            palette[color_index * depth + n];
×
727
                        palette_value_float
728
                            = sixel_pixelformat_byte_to_float(
×
729
                                  context->pixelformat,
730
                                  n,
731
                                  palette_value);
732
                    }
733
                }
734
                error = source_pixel[n] - palette_value_float;
×
735
                if (error < 0.0f) {
×
736
                    diff = (int)(-error * 255.0f + 0.5f);
×
737
                } else {
738
                    diff = (int)(error * 255.0f + 0.5f);
×
739
                }
740
                if (diff > 255) {
×
741
                    diff = 255;
×
742
                }
743
                table_index = diff;
×
744
                if (use_carry) {
×
745
                    varerr_diffuse_carry(carry_curr,
×
746
                                         carry_next,
747
                                         carry_far,
748
                                         context->width,
749
                                         context->height,
750
                                         depth,
751
                                         x,
752
                                         y,
753
                                         error,
754
                                         table_index,
755
                                         direction,
756
                                         n);
757
                } else {
758
                    varerr_diffuse(data + n,
×
759
                                   context->width,
760
                                   context->height,
761
                                   x,
762
                                   y,
763
                                   depth,
764
                                   error,
765
                                   table_index,
766
                                   direction,
767
                                   context->pixelformat,
768
                                   n);
769
                }
770
            }
771
        }
772

773
        if (use_carry) {
×
774
            float *tmp;
775

776
            tmp = carry_curr;
×
777
            carry_curr = carry_next;
×
778
            carry_next = carry_far;
×
779
            carry_far = tmp;
×
780
            if (carry_len > 0) {
×
781
                memset(carry_far, 0x00, carry_len * sizeof(float));
×
782
            }
783
        }
784
        if (absolute_y >= context->output_start) {
×
785
            sixel_dither_pipeline_row_notify(dither, absolute_y);
×
786
        }
787
    }
788

789
    if (optimize_palette) {
×
790
        memcpy(palette, new_palette, (size_t)(*ncolors * depth));
×
791
        if (palette_float != NULL
×
792
                && new_palette_float != NULL
×
793
                && float_depth > 0) {
×
794
            memcpy(palette_float,
×
795
                   new_palette_float,
UNCOV
796
                   (size_t)(*ncolors * float_depth)
×
797
                       * sizeof(float));
798
        }
799
    } else {
800
        *ncolors = reqcolor;
×
801
    }
802

803
    status = SIXEL_OK;
×
804

UNCOV
805
end:
×
806
    free(carry_curr);
×
807
    free(carry_next);
×
808
    free(carry_far);
×
809
    return status;
×
810
}
811

812
/* emacs Local Variables:      */
813
/* emacs mode: c               */
814
/* emacs tab-width: 4          */
815
/* emacs indent-tabs-mode: nil */
816
/* emacs c-basic-offset: 4     */
817
/* emacs End:                  */
818
/* vim: set expandtab ts=4 sts=4 sw=4 : */
819
/* EOF */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc