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

saitoha / libsixel / 19934796867

04 Dec 2025 03:42PM UTC coverage: 43.522% (+2.3%) from 41.258%
19934796867

push

github

saitoha
python: update shared api.py

10714 of 38654 branches covered (27.72%)

14673 of 33714 relevant lines covered (43.52%)

2910517.57 hits per line

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

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

25
#include "config.h"
26

27
/* STDC_HEADERS */
28
#include <stdio.h>
29
#include <stdlib.h>
30

31
#if HAVE_MATH_H
32
# include <math.h>
33
#endif  /* HAVE_MATH_H */
34

35
#if HAVE_MEMORY_H
36
# include <memory.h>
37
#endif  /* HAVE_MEMORY_H */
38

39
#include <sixel.h>
40

41
#include "pixelformat.h"
42

43
#define SIXEL_OKLAB_AB_FLOAT_MIN (-0.5f)
44
#define SIXEL_OKLAB_AB_FLOAT_MAX (0.5f)
45
#define SIXEL_CIELAB_AB_FLOAT_MIN (-1.5f)
46
#define SIXEL_CIELAB_AB_FLOAT_MAX (1.5f)
47
#define SIXEL_CIELAB_L_FLOAT_MIN  (0.0f)
48
#define SIXEL_CIELAB_L_FLOAT_MAX  (1.0f)
49
#define SIXEL_DIN99D_L_FLOAT_MIN  (0.0f)
50
#define SIXEL_DIN99D_L_FLOAT_MAX  (1.0f)
51
#define SIXEL_DIN99D_AB_FLOAT_MIN (-1.0f)
52
#define SIXEL_DIN99D_AB_FLOAT_MAX (1.0f)
53

54
/*
55
 * Normalize a float32 channel stored in the 0.0-1.0 range and convert
56
 * the value to an 8-bit sample. Out-of-range or NaN inputs are clamped
57
 * to sane defaults so downstream conversions always receive valid bytes.
58
 */
59
static unsigned char
60
sixel_pixelformat_float_to_byte(float value)
×
61
{
62
#if HAVE_MATH_H
63
    if (!isfinite(value)) {
×
64
        value = 0.0f;
65
    }
66
#endif  /* HAVE_MATH_H */
67

68
    if (value <= 0.0f) {
×
69
        return 0;
70
    }
71
    if (value >= 1.0f) {
×
72
        return 255;
73
    }
74

75
    return (unsigned char)(value * 255.0f + 0.5f);
×
76
}
77

78
static unsigned char
79
sixel_pixelformat_oklab_L_to_byte(float value)
×
80
{
81
#if HAVE_MATH_H
82
    if (!isfinite(value)) {
×
83
        value = 0.0f;
84
    }
85
#endif  /* HAVE_MATH_H */
86

87
    if (value <= 0.0f) {
×
88
        return 0;
89
    }
90
    if (value >= 1.0f) {
×
91
        return 255;
92
    }
93

94
    return (unsigned char)(value * 255.0f + 0.5f);
×
95
}
96

97
static unsigned char
98
sixel_pixelformat_oklab_ab_to_byte(float value)
×
99
{
100
    float encoded;
×
101

102
#if HAVE_MATH_H
103
    if (!isfinite(value)) {
×
104
        value = 0.0f;
105
    }
106
#endif  /* HAVE_MATH_H */
107

108
    encoded = value + 0.5f;
×
109
    if (encoded <= 0.0f) {
×
110
        return 0;
111
    }
112
    if (encoded >= 1.0f) {
×
113
        return 255;
114
    }
115

116
    return (unsigned char)(encoded * 255.0f + 0.5f);
×
117
}
118

119
static unsigned char
120
sixel_pixelformat_cielab_L_to_byte(float value)
×
121
{
122
#if HAVE_MATH_H
123
    if (!isfinite(value)) {
×
124
        value = 0.0f;
125
    }
126
#endif  /* HAVE_MATH_H */
127

128
    if (value <= 0.0f) {
×
129
        return 0;
130
    }
131
    if (value >= 1.0f) {
×
132
        return 255;
133
    }
134

135
    return (unsigned char)(value * 255.0f + 0.5f);
×
136
}
137

138
static unsigned char
139
sixel_pixelformat_cielab_ab_to_byte(float value)
×
140
{
141
    float encoded;
×
142

143
#if HAVE_MATH_H
144
    if (!isfinite(value)) {
×
145
        value = 0.0f;
×
146
    }
147
#endif  /* HAVE_MATH_H */
148

149
    encoded = (value / (2.0f * SIXEL_CIELAB_AB_FLOAT_MAX)) + 0.5f;
×
150
    if (encoded <= 0.0f) {
×
151
        return 0;
152
    }
153
    if (encoded >= 1.0f) {
×
154
        return 255;
155
    }
156

157
    return (unsigned char)(encoded * 255.0f + 0.5f);
×
158
}
159

160
static unsigned char
161
sixel_pixelformat_din99d_L_to_byte(float value)
×
162
{
163
#if HAVE_MATH_H
164
    if (!isfinite(value)) {
×
165
        value = 0.0f;
166
    }
167
#endif  /* HAVE_MATH_H */
168

169
    if (value <= 0.0f) {
×
170
        return 0;
171
    }
172
    if (value >= 1.0f) {
×
173
        return 255;
174
    }
175

176
    return (unsigned char)(value * 255.0f + 0.5f);
×
177
}
178

179
static unsigned char
180
sixel_pixelformat_din99d_ab_to_byte(float value)
×
181
{
182
    float encoded;
×
183

184
#if HAVE_MATH_H
185
    if (!isfinite(value)) {
×
186
        value = 0.0f;
×
187
    }
188
#endif  /* HAVE_MATH_H */
189

190
    encoded = (value / (2.0f * SIXEL_DIN99D_AB_FLOAT_MAX)) + 0.5f;
×
191
    if (encoded <= 0.0f) {
×
192
        return 0;
193
    }
194
    if (encoded >= 1.0f) {
×
195
        return 255;
196
    }
197

198
    return (unsigned char)(encoded * 255.0f + 0.5f);
×
199
}
200

201
static float
202
sixel_pixelformat_float_channel_min_internal(int pixelformat,
×
203
                                             int channel)
204
{
205
    (void)channel;
×
206
    if (pixelformat == SIXEL_PIXELFORMAT_OKLABFLOAT32) {
×
207
        if (channel == 0) {
×
208
            return 0.0f;
209
        }
210
        return SIXEL_OKLAB_AB_FLOAT_MIN;
×
211
    }
212
    if (pixelformat == SIXEL_PIXELFORMAT_CIELABFLOAT32) {
×
213
        if (channel == 0) {
×
214
            return SIXEL_CIELAB_L_FLOAT_MIN;
215
        }
216
        return SIXEL_CIELAB_AB_FLOAT_MIN;
×
217
    }
218
    if (pixelformat == SIXEL_PIXELFORMAT_DIN99DFLOAT32) {
×
219
        if (channel == 0) {
×
220
            return SIXEL_DIN99D_L_FLOAT_MIN;
221
        }
222
        return SIXEL_DIN99D_AB_FLOAT_MIN;
×
223
    }
224
    return 0.0f;
225
}
226

227
static float
228
sixel_pixelformat_float_channel_max_internal(int pixelformat,
×
229
                                             int channel)
230
{
231
    (void)channel;
×
232
    if (pixelformat == SIXEL_PIXELFORMAT_OKLABFLOAT32) {
×
233
        if (channel == 0) {
×
234
            return 1.0f;
235
        }
236
        return SIXEL_OKLAB_AB_FLOAT_MAX;
237
    }
238
    if (pixelformat == SIXEL_PIXELFORMAT_CIELABFLOAT32) {
×
239
        if (channel == 0) {
×
240
            return SIXEL_CIELAB_L_FLOAT_MAX;
241
        }
242
        return SIXEL_CIELAB_AB_FLOAT_MAX;
243
    }
244
    if (pixelformat == SIXEL_PIXELFORMAT_DIN99DFLOAT32) {
×
245
        if (channel == 0) {
×
246
            return SIXEL_DIN99D_L_FLOAT_MAX;
247
        }
248
        return SIXEL_DIN99D_AB_FLOAT_MAX;
249
    }
250
    return 1.0f;
251
}
252

253
float
254
sixel_pixelformat_float_channel_clamp(int pixelformat,
×
255
                                      int channel,
256
                                      float value)
257
{
258
    float minimum;
×
259
    float maximum;
×
260

261
#if HAVE_MATH_H
262
    if (!isfinite(value)) {
×
263
        value = 0.0f;
×
264
    }
265
#endif  /* HAVE_MATH_H */
266

267
    minimum = sixel_pixelformat_float_channel_min_internal(pixelformat,
×
268
                                                           channel);
269
    maximum = sixel_pixelformat_float_channel_max_internal(pixelformat,
×
270
                                                           channel);
271
    if (value < minimum) {
×
272
        return minimum;
273
    }
274
    if (value > maximum) {
×
275
        return maximum;
276
    }
277

278
    return value;
279
}
280

281
unsigned char
282
sixel_pixelformat_float_channel_to_byte(int pixelformat,
×
283
                                        int channel,
284
                                        float value)
285
{
286
    float clamped;
×
287

288
    clamped = sixel_pixelformat_float_channel_clamp(pixelformat,
×
289
                                                    channel,
290
                                                    value);
291
    if (pixelformat == SIXEL_PIXELFORMAT_OKLABFLOAT32) {
×
292
        if (channel == 0) {
×
293
            return sixel_pixelformat_oklab_L_to_byte(clamped);
×
294
        }
295
        return sixel_pixelformat_oklab_ab_to_byte(clamped);
×
296
    }
297
    if (pixelformat == SIXEL_PIXELFORMAT_CIELABFLOAT32) {
×
298
        if (channel == 0) {
×
299
            return sixel_pixelformat_cielab_L_to_byte(clamped);
×
300
        }
301
        return sixel_pixelformat_cielab_ab_to_byte(clamped);
×
302
    }
303
    if (pixelformat == SIXEL_PIXELFORMAT_DIN99DFLOAT32) {
×
304
        if (channel == 0) {
×
305
            return sixel_pixelformat_din99d_L_to_byte(clamped);
×
306
        }
307
        return sixel_pixelformat_din99d_ab_to_byte(clamped);
×
308
    }
309

310
    (void)channel;
×
311
    return sixel_pixelformat_float_to_byte(clamped);
×
312
}
313

314
float
315
sixel_pixelformat_byte_to_float(int pixelformat,
×
316
                                int channel,
317
                                unsigned char value)
318
{
319
    float decoded;
×
320

321
    if (pixelformat == SIXEL_PIXELFORMAT_OKLABFLOAT32) {
×
322
        if (channel == 0) {
×
323
            return (float)value / 255.0f;
×
324
        }
325
        decoded = (float)value / 255.0f;
×
326
        return decoded - 0.5f;
×
327
    }
328
    if (pixelformat == SIXEL_PIXELFORMAT_CIELABFLOAT32) {
×
329
        if (channel == 0) {
×
330
            return (float)value / 255.0f;
×
331
        }
332
        decoded = (float)value / 255.0f;
×
333
        decoded = (decoded - 0.5f)
×
334
                 * (2.0f * SIXEL_CIELAB_AB_FLOAT_MAX);
335
        return decoded;
×
336
    }
337
    if (pixelformat == SIXEL_PIXELFORMAT_DIN99DFLOAT32) {
×
338
        if (channel == 0) {
×
339
            return (float)value / 255.0f;
×
340
        }
341
        decoded = (float)value / 255.0f;
×
342
        decoded = (decoded - 0.5f)
×
343
                 * (2.0f * SIXEL_DIN99D_AB_FLOAT_MAX);
344
        return decoded;
×
345
    }
346

347
    (void)channel;
×
348
    return (float)value / 255.0f;
×
349
}
350

351
static void
352
get_rgb(unsigned char const *data,
×
353
        int const pixelformat,
354
        int depth,
355
        unsigned char *r,
356
        unsigned char *g,
357
        unsigned char *b)
358
{
359
    unsigned int pixels = 0;
×
360
#if SWAP_BYTES
361
    unsigned int low;
362
    unsigned int high;
363
#endif
364
    int count = 0;
×
365

366
    if (pixelformat == SIXEL_PIXELFORMAT_RGBFLOAT32
×
367
            || pixelformat == SIXEL_PIXELFORMAT_LINEARRGBFLOAT32) {
×
368
        float const *fpixels = (float const *)(void const *)data;
×
369

370
        *r = sixel_pixelformat_float_to_byte(fpixels[0]);
×
371
        *g = sixel_pixelformat_float_to_byte(fpixels[1]);
×
372
        *b = sixel_pixelformat_float_to_byte(fpixels[2]);
×
373
        return;
×
374
    }
375
    if (pixelformat == SIXEL_PIXELFORMAT_OKLABFLOAT32) {
×
376
        float const *fpixels = (float const *)(void const *)data;
×
377

378
        *r = sixel_pixelformat_oklab_L_to_byte(fpixels[0]);
×
379
        *g = sixel_pixelformat_oklab_ab_to_byte(fpixels[1]);
×
380
        *b = sixel_pixelformat_oklab_ab_to_byte(fpixels[2]);
×
381
        return;
×
382
    }
383
    if (pixelformat == SIXEL_PIXELFORMAT_CIELABFLOAT32) {
×
384
        float const *fpixels = (float const *)(void const *)data;
×
385

386
        *r = sixel_pixelformat_cielab_L_to_byte(fpixels[0]);
×
387
        *g = sixel_pixelformat_cielab_ab_to_byte(fpixels[1]);
×
388
        *b = sixel_pixelformat_cielab_ab_to_byte(fpixels[2]);
×
389
        return;
×
390
    }
391
    if (pixelformat == SIXEL_PIXELFORMAT_DIN99DFLOAT32) {
×
392
        float const *fpixels = (float const *)(void const *)data;
×
393

394
        *r = sixel_pixelformat_din99d_L_to_byte(fpixels[0]);
×
395
        *g = sixel_pixelformat_din99d_ab_to_byte(fpixels[1]);
×
396
        *b = sixel_pixelformat_din99d_ab_to_byte(fpixels[2]);
×
397
        return;
×
398
    }
399

400
    while (count < depth) {
×
401
        pixels = *(data + count) | (pixels << 8);
×
402
        count++;
×
403
    }
404

405
    /* TODO: we should swap bytes (only necessary on LSByte first hardware?) */
406
#if SWAP_BYTES
407
    if (depth == 2) {
408
        low    = pixels & 0xff;
409
        high   = (pixels >> 8) & 0xff;
410
        pixels = (low << 8) | high;
411
    }
412
#endif
413

414
    switch (pixelformat) {
×
415
    case SIXEL_PIXELFORMAT_RGB555:
×
416
        *r = ((pixels >> 10) & 0x1f) << 3;
×
417
        *g = ((pixels >>  5) & 0x1f) << 3;
×
418
        *b = ((pixels >>  0) & 0x1f) << 3;
×
419
        break;
×
420
    case SIXEL_PIXELFORMAT_RGB565:
×
421
        *r = ((pixels >> 11) & 0x1f) << 3;
×
422
        *g = ((pixels >>  5) & 0x3f) << 2;
×
423
        *b = ((pixels >>  0) & 0x1f) << 3;
×
424
        break;
×
425
    case SIXEL_PIXELFORMAT_RGB888:
×
426
        *r = (pixels >> 16) & 0xff;
×
427
        *g = (pixels >>  8) & 0xff;
×
428
        *b = (pixels >>  0) & 0xff;
×
429
        break;
×
430
    case SIXEL_PIXELFORMAT_BGR555:
×
431
        *r = ((pixels >>  0) & 0x1f) << 3;
×
432
        *g = ((pixels >>  5) & 0x1f) << 3;
×
433
        *b = ((pixels >> 10) & 0x1f) << 3;
×
434
        break;
×
435
    case SIXEL_PIXELFORMAT_BGR565:
×
436
        *r = ((pixels >>  0) & 0x1f) << 3;
×
437
        *g = ((pixels >>  5) & 0x3f) << 2;
×
438
        *b = ((pixels >> 11) & 0x1f) << 3;
×
439
        break;
×
440
    case SIXEL_PIXELFORMAT_BGR888:
×
441
        *r = (pixels >>  0) & 0xff;
×
442
        *g = (pixels >>  8) & 0xff;
×
443
        *b = (pixels >> 16) & 0xff;
×
444
        break;
×
445
    case SIXEL_PIXELFORMAT_RGBA8888:
×
446
        *r = (pixels >> 24) & 0xff;
×
447
        *g = (pixels >> 16) & 0xff;
×
448
        *b = (pixels >>  8) & 0xff;
×
449
        break;
×
450
    case SIXEL_PIXELFORMAT_ARGB8888:
×
451
        *r = (pixels >> 16) & 0xff;
×
452
        *g = (pixels >>  8) & 0xff;
×
453
        *b = (pixels >>  0) & 0xff;
×
454
        break;
×
455
    case SIXEL_PIXELFORMAT_BGRA8888:
×
456
        *r = (pixels >>  8) & 0xff;
×
457
        *g = (pixels >> 16) & 0xff;
×
458
        *b = (pixels >> 24) & 0xff;
×
459
        break;
×
460
    case SIXEL_PIXELFORMAT_ABGR8888:
×
461
        *r = (pixels >>  0) & 0xff;
×
462
        *g = (pixels >>  8) & 0xff;
×
463
        *b = (pixels >> 16) & 0xff;
×
464
        break;
×
465
    case SIXEL_PIXELFORMAT_GA88:
×
466
        *r = *g = *b = (pixels >> 8) & 0xff;
×
467
        break;
×
468
    case SIXEL_PIXELFORMAT_G8:
×
469
    case SIXEL_PIXELFORMAT_AG88:
470
        *r = *g = *b = pixels & 0xff;
×
471
        break;
×
472
    default:
×
473
        *r = *g = *b = 0;
×
474
        break;
×
475
    }
476
}
1!
477

478

479
SIXELAPI int
480
sixel_helper_compute_depth(int pixelformat)
2,007✔
481
{
482
    int depth = (-1);  /* unknown */
2,007✔
483

484
    switch (pixelformat) {
2,007!
485
    case SIXEL_PIXELFORMAT_ARGB8888:
×
486
    case SIXEL_PIXELFORMAT_RGBA8888:
487
    case SIXEL_PIXELFORMAT_ABGR8888:
488
    case SIXEL_PIXELFORMAT_BGRA8888:
489
        depth = 4;
×
490
        break;
×
491
    case SIXEL_PIXELFORMAT_RGB888:
1,326✔
492
    case SIXEL_PIXELFORMAT_BGR888:
493
        depth = 3;
1,326✔
494
        break;
1,326✔
495
    case SIXEL_PIXELFORMAT_RGB555:
×
496
    case SIXEL_PIXELFORMAT_RGB565:
497
    case SIXEL_PIXELFORMAT_BGR555:
498
    case SIXEL_PIXELFORMAT_BGR565:
499
    case SIXEL_PIXELFORMAT_AG88:
500
    case SIXEL_PIXELFORMAT_GA88:
501
        depth = 2;
×
502
        break;
×
503
    case SIXEL_PIXELFORMAT_G1:
228✔
504
    case SIXEL_PIXELFORMAT_G2:
505
    case SIXEL_PIXELFORMAT_G4:
506
    case SIXEL_PIXELFORMAT_G8:
507
    case SIXEL_PIXELFORMAT_PAL1:
508
    case SIXEL_PIXELFORMAT_PAL2:
509
    case SIXEL_PIXELFORMAT_PAL4:
510
    case SIXEL_PIXELFORMAT_PAL8:
511
        depth = 1;
228✔
512
        break;
228✔
513
    case SIXEL_PIXELFORMAT_RGBFLOAT32:
453✔
514
    case SIXEL_PIXELFORMAT_LINEARRGBFLOAT32:
515
    case SIXEL_PIXELFORMAT_OKLABFLOAT32:
516
    case SIXEL_PIXELFORMAT_CIELABFLOAT32:
517
    case SIXEL_PIXELFORMAT_DIN99DFLOAT32:
518
        depth = (int)(sizeof(float) * 3);
453✔
519
        break;
453✔
520
    default:
521
        break;
522
    }
523

524
    return depth;
2,007✔
525
}
526

527

528
static void
529
expand_rgb(unsigned char *dst,
×
530
           unsigned char const *src,
531
           int width, int height,
532
           int pixelformat, int depth)
533
{
534
    int x;
×
535
    int y;
×
536
    int dst_offset;
×
537
    int src_offset;
×
538
    unsigned char r, g, b;
×
539

540
    for (y = 0; y < height; y++) {
×
541
        for (x = 0; x < width; x++) {
×
542
            src_offset = depth * (y * width + x);
×
543
            dst_offset = 3 * (y * width + x);
×
544
            get_rgb(src + src_offset, pixelformat, depth, &r, &g, &b);
×
545

546
            *(dst + dst_offset + 0) = r;
×
547
            *(dst + dst_offset + 1) = g;
×
548
            *(dst + dst_offset + 2) = b;
×
549
        }
550
    }
551
}
×
552

553

554
static SIXELSTATUS
555
expand_palette(unsigned char *dst, unsigned char const *src,
×
556
               int width, int height, int const pixelformat)
557
{
558
    SIXELSTATUS status = SIXEL_FALSE;
×
559
    int x;
×
560
    int y;
×
561
    int i;
×
562
    int bpp;  /* bit per plane */
×
563

564
    switch (pixelformat) {
×
565
    case SIXEL_PIXELFORMAT_PAL1:
566
    case SIXEL_PIXELFORMAT_G1:
567
        bpp = 1;
568
        break;
569
    case SIXEL_PIXELFORMAT_PAL2:
×
570
    case SIXEL_PIXELFORMAT_G2:
571
        bpp = 2;
×
572
        break;
×
573
    case SIXEL_PIXELFORMAT_PAL4:
×
574
    case SIXEL_PIXELFORMAT_G4:
575
        bpp = 4;
×
576
        break;
×
577
    case SIXEL_PIXELFORMAT_PAL8:
578
    case SIXEL_PIXELFORMAT_G8:
579
        for (i = 0; i < width * height; ++i, ++src) {
×
580
            *dst++ = *src;
×
581
        }
582
        status = SIXEL_OK;
×
583
        goto end;
×
584
    default:
×
585
        status = SIXEL_BAD_ARGUMENT;
×
586
        sixel_helper_set_additional_message(
×
587
            "expand_palette: invalid pixelformat.");
588
        goto end;
×
589
    }
590

591
#if HAVE_DEBUG
592
    fprintf(stderr, "expanding PAL%d to PAL8...\n", bpp);
×
593
#endif
594

595
    for (y = 0; y < height; ++y) {
×
596
        for (x = 0; x < width * bpp / 8; ++x) {
×
597
            for (i = 0; i < 8 / bpp; ++i) {
×
598
                *dst++ = *src >> (8 / bpp - 1 - i) * bpp & ((1 << bpp) - 1);
×
599
            }
600
            src++;
×
601
        }
602
        x = width - x * 8 / bpp;
×
603
        if (x > 0) {
×
604
            for (i = 0; i < x; ++i) {
×
605
                *dst++ = *src >> (8 - (i + 1) * bpp) & ((1 << bpp) - 1);
×
606
            }
607
            src++;
×
608
        }
609
    }
610

611
    status = SIXEL_OK;
612

613
end:
×
614
    return status;
×
615
}
616

617

618
SIXELAPI SIXELSTATUS
619
sixel_helper_normalize_pixelformat(
×
620
    unsigned char       /* out */ *dst,             /* destination buffer */
621
    int                 /* out */ *dst_pixelformat, /* converted pixelformat */
622
    unsigned char const /* in */  *src,             /* source pixels */
623
    int                 /* in */  src_pixelformat,  /* format of source image */
624
    int                 /* in */  width,            /* width of source image */
625
    int                 /* in */  height)           /* height of source image */
626
{
627
    SIXELSTATUS status = SIXEL_FALSE;
×
628
    int depth;
×
629

630
    switch (src_pixelformat) {
×
631
    case SIXEL_PIXELFORMAT_G8:
×
632
        expand_rgb(dst, src, width, height, src_pixelformat, 1);
×
633
        *dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
634
        break;
×
635
    case SIXEL_PIXELFORMAT_RGB565:
×
636
    case SIXEL_PIXELFORMAT_RGB555:
637
    case SIXEL_PIXELFORMAT_BGR565:
638
    case SIXEL_PIXELFORMAT_BGR555:
639
    case SIXEL_PIXELFORMAT_GA88:
640
    case SIXEL_PIXELFORMAT_AG88:
641
        expand_rgb(dst, src, width, height, src_pixelformat, 2);
×
642
        *dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
643
        break;
×
644
    case SIXEL_PIXELFORMAT_RGB888:
×
645
    case SIXEL_PIXELFORMAT_BGR888:
646
        expand_rgb(dst, src, width, height, src_pixelformat, 3);
×
647
        *dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
648
        break;
×
649
    case SIXEL_PIXELFORMAT_RGBFLOAT32:
×
650
    case SIXEL_PIXELFORMAT_LINEARRGBFLOAT32:
651
    case SIXEL_PIXELFORMAT_OKLABFLOAT32:
652
    case SIXEL_PIXELFORMAT_CIELABFLOAT32:
653
    case SIXEL_PIXELFORMAT_DIN99DFLOAT32:
654
        depth = sixel_helper_compute_depth(src_pixelformat);
×
655
        if (depth <= 0) {
×
656
            status = SIXEL_BAD_ARGUMENT;
×
657
            goto end;
×
658
        }
659
        expand_rgb(dst, src, width, height, src_pixelformat, depth);
×
660
        *dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
661
        break;
×
662
    case SIXEL_PIXELFORMAT_RGBA8888:
×
663
    case SIXEL_PIXELFORMAT_ARGB8888:
664
    case SIXEL_PIXELFORMAT_BGRA8888:
665
    case SIXEL_PIXELFORMAT_ABGR8888:
666
        expand_rgb(dst, src, width, height, src_pixelformat, 4);
×
667
        *dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
668
        break;
×
669
    case SIXEL_PIXELFORMAT_PAL1:
×
670
    case SIXEL_PIXELFORMAT_PAL2:
671
    case SIXEL_PIXELFORMAT_PAL4:
672
        *dst_pixelformat = SIXEL_PIXELFORMAT_PAL8;
×
673
        status = expand_palette(dst, src, width, height, src_pixelformat);
×
674
        if (SIXEL_FAILED(status)) {
×
675
            goto end;
×
676
        }
677
        break;
678
    case SIXEL_PIXELFORMAT_G1:
×
679
    case SIXEL_PIXELFORMAT_G2:
680
    case SIXEL_PIXELFORMAT_G4:
681
        *dst_pixelformat = SIXEL_PIXELFORMAT_G8;
×
682
        status = expand_palette(dst, src, width, height, src_pixelformat);
×
683
        if (SIXEL_FAILED(status)) {
×
684
            goto end;
×
685
        }
686
        break;
687
    case SIXEL_PIXELFORMAT_PAL8:
×
688
        memcpy(dst, src, (size_t)(width * height));
×
689
        *dst_pixelformat = src_pixelformat;
×
690
        break;
×
691
    default:
×
692
        status = SIXEL_BAD_ARGUMENT;
×
693
        goto end;
×
694
    }
695

696
    status = SIXEL_OK;
697

698
end:
×
699
    return status;
×
700
}
701

702

703
#if HAVE_TESTS
704
static int
705
test1(void)
×
706
{
707
    unsigned char dst[3];
×
708
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
709
    int src_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
710
    unsigned char src[] = { 0x46, 0xf3, 0xe5 };
×
711
    int ret = 0;
×
712

713
    int nret = EXIT_FAILURE;
×
714

715
    ret = sixel_helper_normalize_pixelformat(dst,
×
716
                                             &dst_pixelformat,
717
                                             src,
718
                                             src_pixelformat,
719
                                             1,
720
                                             1);
721
    if (ret != 0) {
×
722
        goto error;
×
723
    }
724
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
725
        goto error;
×
726
    }
727
    if ((dst[0] << 16 | dst[1] << 8 | dst[2]) != (src[0] << 16 | src[1] << 8 | src[2])) {
×
728
        goto error;
×
729
    }
730
    return EXIT_SUCCESS;
731

732
error:
×
733
    perror("test1");
×
734
    return nret;
×
735
}
736

737

738
static int
739
test2(void)
×
740
{
741
    unsigned char dst[3];
×
742
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
743
    int src_pixelformat = SIXEL_PIXELFORMAT_RGB555;
×
744
    unsigned char src[] = { 0x47, 0x9c };
×
745
    int ret = 0;
×
746

747
    int nret = EXIT_FAILURE;
×
748

749
    ret = sixel_helper_normalize_pixelformat(dst,
×
750
                                             &dst_pixelformat,
751
                                             src,
752
                                             src_pixelformat,
753
                                             1,
754
                                             1);
755
    if (ret != 0) {
×
756
        goto error;
×
757
    }
758
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
759
        goto error;
×
760
    }
761
    if ((dst[0] >> 3 << 10 | dst[1] >> 3 << 5 | dst[2] >> 3) != (src[0] << 8 | src[1])) {
×
762
        goto error;
×
763
    }
764
    return EXIT_SUCCESS;
765

766
error:
×
767
    perror("test2");
×
768
    return nret;
×
769
}
770

771

772
static int
773
test3(void)
×
774
{
775
    unsigned char dst[3];
×
776
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
777
    int src_pixelformat = SIXEL_PIXELFORMAT_RGB565;
×
778
    unsigned char src[] = { 0x47, 0x9c };
×
779
    int ret = 0;
×
780

781
    int nret = EXIT_FAILURE;
×
782

783
    ret = sixel_helper_normalize_pixelformat(dst,
×
784
                                             &dst_pixelformat,
785
                                             src,
786
                                             src_pixelformat,
787
                                             1,
788
                                             1);
789
    if (ret != 0) {
×
790
        goto error;
×
791
    }
792
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
793
        goto error;
×
794
    }
795
    if ((dst[0] >> 3 << 11 | dst[1] >> 2 << 5 | dst[2] >> 3) != (src[0] << 8 | src[1])) {
×
796
        goto error;
×
797
    }
798
    return EXIT_SUCCESS;
799

800
error:
×
801
    perror("test3");
×
802
    return nret;
×
803
}
804

805

806
static int
807
test4(void)
×
808
{
809
    unsigned char dst[3];
×
810
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
811
    int src_pixelformat = SIXEL_PIXELFORMAT_BGR888;
×
812
    unsigned char src[] = { 0x46, 0xf3, 0xe5 };
×
813
    int ret = 0;
×
814

815
    int nret = EXIT_FAILURE;
×
816

817
    ret = sixel_helper_normalize_pixelformat(dst,
×
818
                                             &dst_pixelformat,
819
                                             src,
820
                                             src_pixelformat,
821
                                             1,
822
                                             1);
823
    if (ret != 0) {
×
824
        goto error;
×
825
    }
826
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
827
        goto error;
×
828
    }
829
    if ((dst[2] << 16 | dst[1] << 8 | dst[0]) != (src[0] << 16 | src[1] << 8 | src[2])) {
×
830
        goto error;
×
831
    }
832
    return EXIT_SUCCESS;
833

834
error:
×
835
    perror("test4");
×
836
    return nret;
×
837
}
838

839

840
static int
841
test5(void)
×
842
{
843
    unsigned char dst[3];
×
844
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
845
    int src_pixelformat = SIXEL_PIXELFORMAT_BGR555;
×
846
    unsigned char src[] = { 0x23, 0xc8 };
×
847
    int ret = 0;
×
848

849
    int nret = EXIT_FAILURE;
×
850

851
    ret = sixel_helper_normalize_pixelformat(dst,
×
852
                                             &dst_pixelformat,
853
                                             src,
854
                                             src_pixelformat,
855
                                             1,
856
                                             1);
857
    if (ret != 0) {
×
858
        goto error;
×
859
    }
860
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
861
        goto error;
×
862
    }
863
    if ((dst[2] >> 3 << 10 | dst[1] >> 3 << 5 | dst[0] >> 3) != (src[0] << 8 | src[1])) {
×
864
        goto error;
×
865
    }
866
    return EXIT_SUCCESS;
867

868
error:
×
869
    perror("test5");
×
870
    return nret;
×
871
}
872

873

874
static int
875
test6(void)
×
876
{
877
    unsigned char dst[3];
×
878
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
879
    int src_pixelformat = SIXEL_PIXELFORMAT_BGR565;
×
880
    unsigned char src[] = { 0x47, 0x88 };
×
881
    int ret = 0;
×
882

883
    int nret = EXIT_FAILURE;
×
884

885
    ret = sixel_helper_normalize_pixelformat(dst,
×
886
                                             &dst_pixelformat,
887
                                             src,
888
                                             src_pixelformat,
889
                                             1,
890
                                             1);
891
    if (ret != 0) {
×
892
        goto error;
×
893
    }
894
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
895
        goto error;
×
896
    }
897
    if ((dst[2] >> 3 << 11 | dst[1] >> 2 << 5 | dst[0] >> 3) != (src[0] << 8 | src[1])) {
×
898
        goto error;
×
899
    }
900
    return EXIT_SUCCESS;
901

902
error:
×
903
    perror("test6");
×
904
    return nret;
×
905
}
906

907

908
static int
909
test7(void)
×
910
{
911
    unsigned char dst[3];
×
912
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
913
    int src_pixelformat = SIXEL_PIXELFORMAT_AG88;
×
914
    unsigned char src[] = { 0x47, 0x88 };
×
915
    int ret = 0;
×
916

917
    int nret = EXIT_FAILURE;
×
918

919
    ret = sixel_helper_normalize_pixelformat(dst,
×
920
                                             &dst_pixelformat,
921
                                             src,
922
                                             src_pixelformat,
923
                                             1,
924
                                             1);
925
    if (ret != 0) {
×
926
        goto error;
×
927
    }
928
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
929
        goto error;
×
930
    }
931
    if (dst[0] != src[1]) {
×
932
        goto error;
×
933
    }
934
    return EXIT_SUCCESS;
935

936
error:
×
937
    perror("test7");
×
938
    return nret;
×
939
}
940

941

942
static int
943
test8(void)
×
944
{
945
    unsigned char dst[3];
×
946
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
947
    int src_pixelformat = SIXEL_PIXELFORMAT_GA88;
×
948
    unsigned char src[] = { 0x47, 0x88 };
×
949
    int ret = 0;
×
950

951
    int nret = EXIT_FAILURE;
×
952

953
    ret = sixel_helper_normalize_pixelformat(dst,
×
954
                                             &dst_pixelformat,
955
                                             src,
956
                                             src_pixelformat,
957
                                             1,
958
                                             1);
959
    if (ret != 0) {
×
960
        goto error;
×
961
    }
962
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
963
        goto error;
×
964
    }
965
    if (dst[0] != src[0]) {
×
966
        goto error;
×
967
    }
968
    return EXIT_SUCCESS;
969

970
error:
×
971
    perror("test8");
×
972
    return nret;
×
973
}
974

975

976
static int
977
test9(void)
×
978
{
979
    unsigned char dst[3];
×
980
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
981
    int src_pixelformat = SIXEL_PIXELFORMAT_RGBA8888;
×
982
    unsigned char src[] = { 0x46, 0xf3, 0xe5, 0xf0 };
×
983
    int ret = 0;
×
984

985
    int nret = EXIT_FAILURE;
×
986

987
    ret = sixel_helper_normalize_pixelformat(dst,
×
988
                                             &dst_pixelformat,
989
                                             src,
990
                                             src_pixelformat,
991
                                             1,
992
                                             1);
993
    if (ret != 0) {
×
994
        goto error;
×
995
    }
996
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
997
        goto error;
×
998
    }
999
    if (dst[0] != src[0]) {
×
1000
        goto error;
×
1001
    }
1002
    if (dst[1] != src[1]) {
×
1003
        goto error;
×
1004
    }
1005
    if (dst[2] != src[2]) {
×
1006
        goto error;
×
1007
    }
1008
    return EXIT_SUCCESS;
1009

1010
error:
×
1011
    perror("test8");
×
1012
    return nret;
×
1013
}
1014

1015

1016
static int
1017
test10(void)
×
1018
{
1019
    unsigned char dst[3];
×
1020
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
1021
    int src_pixelformat = SIXEL_PIXELFORMAT_ARGB8888;
×
1022
    unsigned char src[] = { 0x46, 0xf3, 0xe5, 0xf0 };
×
1023
    int ret = 0;
×
1024

1025
    int nret = EXIT_FAILURE;
×
1026

1027
    ret = sixel_helper_normalize_pixelformat(dst,
×
1028
                                             &dst_pixelformat,
1029
                                             src,
1030
                                             src_pixelformat,
1031
                                             1,
1032
                                             1);
1033
    if (ret != 0) {
×
1034
        goto error;
×
1035
    }
1036
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
1037
        goto error;
×
1038
    }
1039
    if (dst[0] != src[1]) {
×
1040
        goto error;
×
1041
    }
1042
    if (dst[1] != src[2]) {
×
1043
        goto error;
×
1044
    }
1045
    if (dst[2] != src[3]) {
×
1046
        goto error;
×
1047
    }
1048
    return EXIT_SUCCESS;
1049

1050
error:
×
1051
    perror("test8");
×
1052
    return nret;
×
1053
}
1054

1055

1056
static int
1057
test11(void)
×
1058
{
1059
    unsigned char dst[3];
×
1060
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
1061
    int src_pixelformat = SIXEL_PIXELFORMAT_RGBFLOAT32;
×
1062
    float srcf[] = { 0.0f, 0.5f, 1.0f };
×
1063
    unsigned char const *src = (unsigned char const *)srcf;
×
1064
    int ret = 0;
×
1065
    int depth;
×
1066

1067
    int nret = EXIT_FAILURE;
×
1068

1069
    ret = sixel_helper_normalize_pixelformat(dst,
×
1070
                                             &dst_pixelformat,
1071
                                             src,
1072
                                             src_pixelformat,
1073
                                             1,
1074
                                             1);
1075
    if (ret != 0) {
×
1076
        goto error;
×
1077
    }
1078
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
1079
        goto error;
×
1080
    }
1081
    if (dst[0] != 0 || dst[1] != 128 || dst[2] != 255) {
×
1082
        goto error;
×
1083
    }
1084
    depth = sixel_helper_compute_depth(src_pixelformat);
×
1085
    if (depth != (int)(sizeof(float) * 3)) {
×
1086
        goto error;
×
1087
    }
1088
    return EXIT_SUCCESS;
1089

1090
error:
×
1091
    perror("test11");
×
1092
    return nret;
×
1093
}
1094

1095

1096
SIXELAPI int
1097
sixel_pixelformat_tests_main(void)
×
1098
{
1099
    int nret = EXIT_FAILURE;
×
1100
    size_t i;
×
1101
    typedef int (* testcase)(void);
×
1102

1103
    static testcase const testcases[] = {
×
1104
        test1,
1105
        test2,
1106
        test3,
1107
        test4,
1108
        test5,
1109
        test6,
1110
        test7,
1111
        test8,
1112
        test9,
1113
        test10,
1114
        test11,
1115
    };
1116

1117
    for (i = 0; i < sizeof(testcases) / sizeof(testcase); ++i) {
×
1118
        nret = testcases[i]();
×
1119
        if (nret != EXIT_SUCCESS) {
×
1120
            goto error;
×
1121
        }
1122
    }
1123

1124
    nret = EXIT_SUCCESS;
1125

1126
error:
×
1127
    return nret;
×
1128
}
1129
#endif  /* HAVE_TESTS */
1130

1131
/* emacs Local Variables:      */
1132
/* emacs mode: c               */
1133
/* emacs tab-width: 4          */
1134
/* emacs indent-tabs-mode: nil */
1135
/* emacs c-basic-offset: 4     */
1136
/* emacs End:                  */
1137
/* vim: set expandtab ts=4 sts=4 sw=4 : */
1138
/* 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