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

saitoha / libsixel / 29651119742

18 Jul 2026 02:41PM UTC coverage: 85.03% (-0.3%) from 85.292%
29651119742

push

github

saitoha
fix: clip size fill for transparent offset bands

79318 of 144774 branches covered (54.79%)

4 of 6 new or added lines in 1 file covered. (66.67%)

3156 existing lines in 22 files now uncovered.

141353 of 166238 relevant lines covered (85.03%)

6269019.35 hits per line

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

76.53
/src/sixel_decode_pixels.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
 * Shared SIXEL memory decoding helper for packed pixel output.
26
 */
27

28
#if defined(HAVE_CONFIG_H)
29
#include "config.h"
30
#endif
31

32
#include <limits.h>
33
#include <stddef.h>
34
#include <stdlib.h>
35
#include <string.h>
36
#if HAVE_STDINT_H
37
# include <stdint.h>
38
#endif  /* HAVE_STDINT_H */
39

40
#ifndef SIZE_MAX
41
# define SIZE_MAX ((size_t)-1)
42
#endif  /* SIZE_MAX */
43

44
#include <sixel.h>
45

46
#include "sixel_decode_pixels.h"
47

48
#define SIXEL_DECODE_MAX_SIZE 6000
49

50
static int
51
sixel_decode_pixels_depth(int pixelformat)
905✔
52
{
53
    switch (pixelformat) {
905!
54
    case SIXEL_PIXELFORMAT_RGB888:
55
    case SIXEL_PIXELFORMAT_BGR888:
56
        return 3;
57
    case SIXEL_PIXELFORMAT_RGBA8888:
456✔
58
    case SIXEL_PIXELFORMAT_ARGB8888:
59
    case SIXEL_PIXELFORMAT_BGRA8888:
60
    case SIXEL_PIXELFORMAT_ABGR8888:
61
    case SIXEL_PIXELFORMAT_XRGB8888:
62
    case SIXEL_PIXELFORMAT_RGBX8888:
63
    case SIXEL_PIXELFORMAT_XBGR8888:
64
    case SIXEL_PIXELFORMAT_BGRX8888:
65
        return 4;
849✔
66
    default:
67
        break;
×
68
    }
69

70
    return 0;
×
71
}
57✔
72

73
static int
74
sixel_decode_pixels_format_has_alpha(int pixelformat)
832✔
75
{
76
    switch (pixelformat) {
832✔
77
    case SIXEL_PIXELFORMAT_RGBA8888:
112✔
78
    case SIXEL_PIXELFORMAT_ARGB8888:
79
    case SIXEL_PIXELFORMAT_BGRA8888:
80
    case SIXEL_PIXELFORMAT_ABGR8888:
81
        return 1;
126✔
82
    default:
304✔
83
        break;
538✔
84
    }
85

86
    return 0;
538✔
87
}
52✔
88

89
static int
90
sixel_decode_pixels_alpha_is_opaque(unsigned char const *rgba,
216✔
91
                                    size_t total)
92
{
93
    size_t i;
94

95
    for (i = 0U; i < total; ++i) {
6,672✔
96
        if (rgba[i * 4U + 3U] != 0xffU) {
6,448✔
97
            return 0;
90✔
98
        }
99
    }
393✔
100

101
    return 1;
126✔
102
}
24✔
103

104
static unsigned char
105
sixel_decode_pixels_blend(unsigned char src,
952✔
106
                          unsigned char bg,
107
                          unsigned int alpha)
108
{
109
    return (unsigned char)(((unsigned int)src * alpha +
1,792✔
110
                            (unsigned int)bg * (255U - alpha)) / 255U);
1,036✔
111
}
112

113
static void
114
sixel_decode_pixels_store(unsigned char *dst,
448✔
115
                          unsigned char const *src,
116
                          int pixelformat,
117
                          unsigned char const *bg)
118
{
119
    unsigned int alpha;
196✔
120
    unsigned char r;
196✔
121
    unsigned char g;
196✔
122
    unsigned char b;
196✔
123

124
    alpha = src[3];
448✔
125
    if (!sixel_decode_pixels_format_has_alpha(pixelformat)) {
448!
126
        r = sixel_decode_pixels_blend(src[0], bg[0], alpha);
448✔
127
        g = sixel_decode_pixels_blend(src[1], bg[1], alpha);
448✔
128
        b = sixel_decode_pixels_blend(src[2], bg[2], alpha);
448✔
129
    } else {
28✔
130
        r = src[0];
×
131
        g = src[1];
×
132
        b = src[2];
×
133
    }
134

135
    switch (pixelformat) {
448!
136
    case SIXEL_PIXELFORMAT_RGB888:
137
        dst[0] = r;
×
138
        dst[1] = g;
×
139
        dst[2] = b;
×
140
        break;
×
141
    case SIXEL_PIXELFORMAT_BGR888:
142
        dst[0] = b;
×
143
        dst[1] = g;
×
144
        dst[2] = r;
×
145
        break;
×
146
    case SIXEL_PIXELFORMAT_RGBA8888:
147
        dst[0] = r;
×
148
        dst[1] = g;
×
149
        dst[2] = b;
×
150
        dst[3] = src[3];
×
151
        break;
×
152
    case SIXEL_PIXELFORMAT_ARGB8888:
153
        dst[0] = src[3];
×
154
        dst[1] = r;
×
155
        dst[2] = g;
×
156
        dst[3] = b;
×
157
        break;
×
158
    case SIXEL_PIXELFORMAT_BGRA8888:
159
        dst[0] = b;
×
160
        dst[1] = g;
×
161
        dst[2] = r;
×
162
        dst[3] = src[3];
×
163
        break;
×
164
    case SIXEL_PIXELFORMAT_ABGR8888:
165
        dst[0] = src[3];
×
166
        dst[1] = b;
×
167
        dst[2] = g;
×
168
        dst[3] = r;
×
169
        break;
×
170
    case SIXEL_PIXELFORMAT_XRGB8888:
30✔
171
        dst[0] = 0xffU;
32✔
172
        dst[1] = r;
32✔
173
        dst[2] = g;
32✔
174
        dst[3] = b;
32✔
175
        break;
32✔
176
    case SIXEL_PIXELFORMAT_RGBX8888:
30✔
177
        dst[0] = r;
32✔
178
        dst[1] = g;
32✔
179
        dst[2] = b;
32✔
180
        dst[3] = 0xffU;
32✔
181
        break;
32✔
182
    case SIXEL_PIXELFORMAT_XBGR8888:
30✔
183
        dst[0] = 0xffU;
32✔
184
        dst[1] = b;
32✔
185
        dst[2] = g;
32✔
186
        dst[3] = r;
32✔
187
        break;
32✔
188
    case SIXEL_PIXELFORMAT_BGRX8888:
330✔
189
        dst[0] = b;
352✔
190
        dst[1] = g;
352✔
191
        dst[2] = r;
352✔
192
        dst[3] = 0xffU;
352✔
193
        break;
352✔
194
    default:
195
        break;
196
    }
197
}
448✔
198

199
static SIXELSTATUS
200
sixel_decode_pixels_convert(unsigned char *decoded,
384✔
201
                            int width,
202
                            int height,
203
                            int pixelformat,
204
                            unsigned char const *bg,
205
                            unsigned char **out_pixels,
206
                            unsigned int *result_flags,
207
                            sixel_allocator_t *allocator)
208
{
209
    SIXELSTATUS status;
168✔
210
    unsigned char *converted;
168✔
211
    unsigned char const *src;
168✔
212
    unsigned char *dst;
168✔
213
    size_t total;
168✔
214
    size_t i;
168✔
215
    int depth;
168✔
216
    int alpha_opaque;
168✔
217

218
    status = SIXEL_FALSE;
384✔
219
    converted = NULL;
384✔
220
    src = NULL;
384✔
221
    dst = NULL;
384✔
222
    total = 0U;
384✔
223
    i = 0U;
384✔
224
    depth = 0;
384✔
225
    alpha_opaque = 0;
384✔
226

227
    if (decoded == NULL || out_pixels == NULL || result_flags == NULL) {
384!
228
        return SIXEL_BAD_ARGUMENT;
229
    }
230
    if (width <= 0 || height <= 0) {
384!
231
        return SIXEL_BAD_INPUT;
232
    }
233

234
    depth = sixel_decode_pixels_depth(pixelformat);
384!
235
    if (depth == 0) {
384!
236
        sixel_helper_set_additional_message(
×
237
            "sixel_decode_pixels: unsupported output pixelformat.");
238
        return SIXEL_BAD_ARGUMENT;
×
239
    }
240

241
    total = (size_t)width * (size_t)height;
384✔
242
    if (total > SIZE_MAX / (size_t)depth) {
384!
243
        sixel_helper_set_additional_message(
244
            "sixel_decode_pixels: image is too large to convert.");
245
        return SIXEL_BAD_ALLOCATION;
246
    }
247

248
    alpha_opaque = sixel_decode_pixels_alpha_is_opaque(decoded, total);
384✔
249
    if (!sixel_decode_pixels_format_has_alpha(pixelformat) || alpha_opaque) {
384✔
250
        *result_flags |= SIXEL_DECODE_PIXELS_RESULT_ALPHA_OPAQUE;
224✔
251
    }
14✔
252

253
    if (pixelformat == SIXEL_PIXELFORMAT_RGBA8888) {
384✔
254
        *out_pixels = decoded;
224✔
255
        return SIXEL_OK;
224✔
256
    }
257

258
    converted = (unsigned char *)sixel_allocator_malloc(
210✔
259
        allocator, total * (size_t)depth);
140✔
260
    if (converted == NULL) {
160!
261
        sixel_helper_set_additional_message(
×
262
            "sixel_decode_pixels: allocation failed for pixel output.");
263
        return SIXEL_BAD_ALLOCATION;
×
264
    }
265

266
    src = decoded;
90✔
267
    dst = converted;
90✔
268
    for (i = 0U; i < total; ++i) {
608✔
269
        sixel_decode_pixels_store(dst, src, pixelformat, bg);
448✔
270
        src += 4;
448✔
271
        dst += depth;
448✔
272
    }
28✔
273

274
    *out_pixels = converted;
160✔
275
    status = SIXEL_OK;
160✔
276

277
    return status;
160✔
278
}
24✔
279

280
SIXEL_INTERNAL_API SIXELSTATUS
281
sixel_decode_pixels_finish_rgba(unsigned char **decoded,
384✔
282
                                int width,
283
                                int height,
284
                                int pixelformat,
285
                                unsigned char const *bg,
286
                                unsigned int result_flags,
287
                                sixel_decode_result_t *result,
288
                                sixel_allocator_t *allocator)
289
{
290
    SIXELSTATUS status;
168✔
291
    unsigned char *converted;
168✔
292
    unsigned char const default_bg[3] = { 0U, 0U, 0U };
384✔
293
    unsigned char const *output_bg;
168✔
294
    int depth;
168✔
295

296
    converted = NULL;
384✔
297
    output_bg = bg;
384✔
298
    depth = 0;
384✔
299

300
    if (decoded == NULL || *decoded == NULL || result == NULL) {
384!
301
        return SIXEL_BAD_ARGUMENT;
302
    }
303
    if (output_bg == NULL) {
384!
304
        output_bg = default_bg;
×
305
    }
306

307
    depth = sixel_decode_pixels_depth(pixelformat);
384!
308
    if (depth == 0) {
384!
309
        sixel_helper_set_additional_message(
×
310
            "sixel_decode_pixels: unsupported output pixelformat.");
311
        return SIXEL_BAD_ARGUMENT;
×
312
    }
313

314
    /* Guard against runaway inputs before exposing the buffer. */
315
    if (width > SIXEL_DECODE_MAX_SIZE || height > SIXEL_DECODE_MAX_SIZE) {
384!
316
        sixel_helper_set_additional_message(
×
317
            "sixel_decode_pixels: image exceeds 6000x6000 pixels.");
318
        return SIXEL_BAD_INPUT;
×
319
    }
320

321
    status = sixel_decode_pixels_convert(*decoded,
408✔
322
                                         width,
24✔
323
                                         height,
24✔
324
                                         pixelformat,
24✔
325
                                         output_bg,
24✔
326
                                         &converted,
327
                                         &result_flags,
328
                                         allocator);
24✔
329
    if (SIXEL_FAILED(status)) {
384!
330
        return status;
331
    }
332
    if (converted != *decoded) {
384✔
333
        if (allocator != NULL) {
160!
334
            sixel_allocator_free(allocator, *decoded);
160✔
335
        } else {
10✔
336
            free(*decoded);
×
337
        }
338
    }
10✔
339
    *decoded = NULL;
384✔
340

341
    result->pixels = converted;
384✔
342
    result->width = width;
384✔
343
    result->height = height;
384✔
344
    result->pixelformat = pixelformat;
384✔
345
    result->stride = width * depth;
384✔
346
    result->flags = result_flags;
384✔
347

348
    return SIXEL_OK;
384✔
349
}
24✔
350

351
static SIXELSTATUS
352
sixel_decode_pixels_try(unsigned char const *data,
128✔
353
                        size_t size,
354
                        unsigned int decode_flags,
355
                        unsigned char **out_pixels,
356
                        int *out_width,
357
                        int *out_height,
358
                        unsigned int *result_flags,
359
                        sixel_allocator_t *allocator)
360
{
361
    SIXELSTATUS status;
56✔
362
    unsigned char *buffer;
56✔
363

364
    if (data == NULL || out_pixels == NULL || out_width == NULL ||
128!
365
            out_height == NULL || result_flags == NULL) {
128!
366
        return SIXEL_BAD_ARGUMENT;
367
    }
368

369
    if (size == 0 || size > (size_t)(INT_MAX - 2)) {
128!
370
        sixel_helper_set_additional_message(
×
371
            "sixel_decode_pixels: invalid input size.");
372
        return SIXEL_BAD_INPUT;
×
373
    }
374

375
    /*
376
     * The historical decoder entry points take mutable buffers, but the parser
377
     * only reads input bytes.  Keep the public memory decoder zero-copy on the
378
     * normal path and allocate a mutable work buffer only for terminator retry.
379
     */
380
    buffer = (unsigned char *)(void const *)data;
128✔
381
    status = sixel_decode_direct_with_options(buffer,
136✔
382
                                              (int)size,
8✔
383
                                              decode_flags,
8✔
384
                                              out_pixels,
8✔
385
                                              out_width,
8✔
386
                                              out_height,
8✔
387
                                              NULL,
388
                                              NULL,
389
                                              result_flags,
8✔
390
                                              allocator);
8✔
391

392
    return status;
128✔
393
}
8✔
394

395
static SIXELSTATUS
UNCOV
396
sixel_decode_pixels_terminated_attempts(unsigned char *workbuf,
×
397
                                        size_t size,
398
                                        unsigned int decode_flags,
399
                                        unsigned char **out_pixels,
400
                                        int *out_width,
401
                                        int *out_height,
402
                                        unsigned int *result_flags,
403
                                        sixel_allocator_t *allocator)
404
{
405
    SIXELSTATUS status;
406
    unsigned int second_flags;
407
    unsigned int third_flags;
408

UNCOV
409
    second_flags = 0U;
×
UNCOV
410
    third_flags = 0U;
×
411

412
    /* Retry with a synthetic BEL terminator for truncated streams. */
UNCOV
413
    workbuf[size] = 0x07U;
×
UNCOV
414
    status = sixel_decode_pixels_try(workbuf,
×
415
                                     size + 1U,
416
                                     decode_flags,
417
                                     out_pixels,
418
                                     out_width,
419
                                     out_height,
420
                                     &second_flags,
421
                                     allocator);
422
    if (status == SIXEL_OK) {
×
UNCOV
423
        *result_flags = second_flags;
×
UNCOV
424
        return status;
×
425
    }
426

427
    /* Retry with ESC \ (ST) in case BEL is not accepted. */
428
    workbuf[size] = 0x1bU;
×
UNCOV
429
    workbuf[size + 1U] = '\\';
×
UNCOV
430
    status = sixel_decode_pixels_try(workbuf,
×
431
                                     size + 2U,
432
                                     decode_flags,
433
                                     out_pixels,
434
                                     out_width,
435
                                     out_height,
436
                                     &third_flags,
437
                                     allocator);
UNCOV
438
    if (status == SIXEL_OK) {
×
UNCOV
439
        *result_flags = third_flags;
×
440
    }
441

442
    return status;
443
}
444

445
SIXELAPI SIXELSTATUS
446
sixel_decode_pixels(unsigned char const *data,
128✔
447
                    size_t size,
448
                    sixel_decode_options_t const *options,
449
                    sixel_decode_result_t *result,
450
                    sixel_allocator_t *allocator)
451
{
452
    SIXELSTATUS status;
56✔
453
    sixel_allocator_t *work_allocator;
56✔
454
    unsigned char *workbuf;
56✔
455
    unsigned char *decoded;
56✔
456
    unsigned char const default_bg[3] = { 0U, 0U, 0U };
128✔
457
    unsigned char const *bg;
56✔
458
    unsigned int decode_flags;
56✔
459
    unsigned int result_flags;
56✔
460
    unsigned int first_flags;
56✔
461
    int width;
56✔
462
    int height;
56✔
463
    int pixelformat;
56✔
464
    int depth;
56✔
465

466
    status = SIXEL_FALSE;
128✔
467
    work_allocator = allocator;
128✔
468
    workbuf = NULL;
128✔
469
    decoded = NULL;
128✔
470
    bg = default_bg;
128✔
471
    decode_flags = 0U;
128✔
472
    result_flags = 0U;
128✔
473
    first_flags = 0U;
128✔
474
    width = 0;
128✔
475
    height = 0;
128✔
476
    pixelformat = SIXEL_PIXELFORMAT_RGBA8888;
128✔
477
    depth = 0;
128✔
478

479
    if (data == NULL || result == NULL) {
128!
480
        return SIXEL_BAD_ARGUMENT;
481
    }
482

483
    result->pixels = NULL;
128✔
484
    result->width = 0;
128✔
485
    result->height = 0;
128✔
486
    result->pixelformat = 0;
128✔
487
    result->stride = 0;
128✔
488
    result->flags = 0U;
128✔
489

490
    if (options != NULL) {
128✔
491
        decode_flags = options->flags;
112✔
492
        if (options->preferred_pixelformat != 0) {
112!
493
            pixelformat = options->preferred_pixelformat;
112✔
494
        }
7✔
495
        bg = options->bgcolor;
112✔
496
    }
7✔
497

498
    depth = sixel_decode_pixels_depth(pixelformat);
121!
499
    if (depth == 0) {
72!
500
        sixel_helper_set_additional_message(
×
501
            "sixel_decode_pixels: unsupported output pixelformat.");
UNCOV
502
        return SIXEL_BAD_ARGUMENT;
×
503
    }
504

505
    if (size == 0 || size > (size_t)(INT_MAX - 2) ||
128!
506
            size > (SIZE_MAX - 2U)) {
8✔
507
        sixel_helper_set_additional_message(
×
508
            "sixel_decode_pixels: invalid input size.");
UNCOV
509
        return SIXEL_BAD_INPUT;
×
510
    }
511

512
    if (work_allocator != NULL) {
128!
513
        sixel_allocator_ref(work_allocator);
128✔
514
    } else {
8✔
UNCOV
515
        status = sixel_allocator_new(&work_allocator,
×
516
                                     NULL,
517
                                     NULL,
518
                                     NULL,
519
                                     NULL);
520
        if (SIXEL_FAILED(status)) {
×
UNCOV
521
            work_allocator = NULL;
×
UNCOV
522
            goto cleanup;
×
523
        }
524
    }
525

526
    status = sixel_decode_pixels_try(data,
136✔
527
                                     size,
8✔
528
                                     decode_flags,
8✔
529
                                     &decoded,
530
                                     &width,
531
                                     &height,
532
                                     &first_flags,
533
                                     work_allocator);
8✔
534
    if (status == SIXEL_OK) {
128!
535
        result_flags = first_flags;
128✔
536
    } else {
8✔
537
        workbuf = (unsigned char *)sixel_allocator_malloc(work_allocator,
×
538
                                                          size + 2U);
539
        if (workbuf == NULL) {
×
UNCOV
540
            status = SIXEL_BAD_ALLOCATION;
×
541
            sixel_helper_set_additional_message(
×
542
                "sixel_decode_pixels: allocation failed for input copy.");
543
            goto cleanup;
×
544
        }
545
        memcpy(workbuf, data, size);
×
546

UNCOV
547
        status = sixel_decode_pixels_terminated_attempts(workbuf,
×
548
                                                         size,
549
                                                         decode_flags,
550
                                                         &decoded,
551
                                                         &width,
552
                                                         &height,
553
                                                         &result_flags,
554
                                                         work_allocator);
UNCOV
555
        if (SIXEL_FAILED(status)) {
×
UNCOV
556
            goto cleanup;
×
557
        }
558
    }
559

560
    status = sixel_decode_pixels_finish_rgba(&decoded,
128✔
561
                                             width,
8✔
562
                                             height,
8✔
563
                                             pixelformat,
8✔
564
                                             bg,
8✔
565
                                             result_flags,
8✔
566
                                             result,
8✔
567
                                             work_allocator);
8✔
568
    if (SIXEL_FAILED(status)) {
128!
UNCOV
569
        goto cleanup;
×
570
    }
571
    status = SIXEL_OK;
72✔
572

573
cleanup:
120✔
574
    if (decoded != NULL) {
128!
UNCOV
575
        sixel_allocator_free(work_allocator, decoded);
×
UNCOV
576
        decoded = NULL;
×
577
    }
578
    if (workbuf != NULL) {
128!
UNCOV
579
        sixel_allocator_free(work_allocator, workbuf);
×
UNCOV
580
        workbuf = NULL;
×
581
    }
582
    if (work_allocator != NULL) {
128!
583
        sixel_allocator_unref(work_allocator);
128✔
584
    }
8✔
585

586
    return status;
72✔
587
}
8✔
588

589
SIXELAPI SIXELSTATUS
590
sixel_decode_pixels_body(unsigned char const *body,
16✔
591
                         size_t body_size,
592
                         int const *params,
593
                         size_t nparams,
594
                         sixel_decode_options_t const *options,
595
                         sixel_decode_result_t *result,
596
                         sixel_allocator_t *allocator)
597
{
598
    SIXELSTATUS status;
7✔
599
    sixel_allocator_t *work_allocator;
7✔
600
    unsigned char *decoded;
7✔
601
    unsigned char *buffer;
7✔
602
    unsigned char empty_body;
7✔
603
    unsigned char const default_bg[3] = { 0U, 0U, 0U };
16✔
604
    unsigned char const *bg;
7✔
605
    unsigned int decode_flags;
7✔
606
    unsigned int result_flags;
7✔
607
    int width;
7✔
608
    int height;
7✔
609
    int pixelformat;
7✔
610
    int depth;
7✔
611

612
    status = SIXEL_FALSE;
16✔
613
    work_allocator = allocator;
16✔
614
    decoded = NULL;
16✔
615
    buffer = NULL;
16✔
616
    empty_body = 0U;
16✔
617
    bg = default_bg;
16✔
618
    decode_flags = 0U;
16✔
619
    result_flags = 0U;
16✔
620
    width = 0;
16✔
621
    height = 0;
16✔
622
    pixelformat = SIXEL_PIXELFORMAT_RGBA8888;
16✔
623
    depth = 0;
16✔
624

625
    if ((body == NULL && body_size != 0U) || result == NULL ||
16!
626
            (params == NULL && nparams != 0U)) {
8!
627
        return SIXEL_BAD_ARGUMENT;
628
    }
629

630
    result->pixels = NULL;
16✔
631
    result->width = 0;
16✔
632
    result->height = 0;
16✔
633
    result->pixelformat = 0;
16✔
634
    result->stride = 0;
16✔
635
    result->flags = 0U;
16✔
636

637
    if (options != NULL) {
16!
638
        decode_flags = options->flags;
16✔
639
        if (options->preferred_pixelformat != 0) {
16!
640
            pixelformat = options->preferred_pixelformat;
16✔
641
        }
1✔
642
        bg = options->bgcolor;
16✔
643
    }
1✔
644

645
    depth = sixel_decode_pixels_depth(pixelformat);
16!
646
    if (depth == 0) {
9!
UNCOV
647
        sixel_helper_set_additional_message(
×
648
            "sixel_decode_pixels_body: unsupported output pixelformat.");
UNCOV
649
        return SIXEL_BAD_ARGUMENT;
×
650
    }
651

652
    if (body_size > (size_t)INT_MAX) {
16!
UNCOV
653
        sixel_helper_set_additional_message(
×
654
            "sixel_decode_pixels_body: invalid input size.");
UNCOV
655
        return SIXEL_BAD_INPUT;
×
656
    }
657

658
    if (work_allocator != NULL) {
16!
659
        sixel_allocator_ref(work_allocator);
16✔
660
    } else {
1✔
UNCOV
661
        status = sixel_allocator_new(&work_allocator,
×
662
                                     NULL,
663
                                     NULL,
664
                                     NULL,
665
                                     NULL);
UNCOV
666
        if (SIXEL_FAILED(status)) {
×
UNCOV
667
            work_allocator = NULL;
×
UNCOV
668
            goto cleanup;
×
669
        }
670
    }
671

672
    buffer = body_size == 0U ? &empty_body : (unsigned char *)(void const *)body;
16!
673
    status = sixel_decode_direct_body_with_options(buffer,
17✔
674
                                                   (int)body_size,
1✔
675
                                                   decode_flags,
1✔
676
                                                   params,
1✔
677
                                                   nparams,
1✔
678
                                                   &decoded,
679
                                                   &width,
680
                                                   &height,
681
                                                   NULL,
682
                                                   NULL,
683
                                                   &result_flags,
684
                                                   work_allocator);
1✔
685
    if (SIXEL_FAILED(status)) {
16!
UNCOV
686
        goto cleanup;
×
687
    }
688

689
    status = sixel_decode_pixels_finish_rgba(&decoded,
16✔
690
                                             width,
1✔
691
                                             height,
1✔
692
                                             pixelformat,
1✔
693
                                             bg,
1✔
694
                                             result_flags,
1✔
695
                                             result,
1✔
696
                                             work_allocator);
1✔
697
    if (SIXEL_FAILED(status)) {
16!
UNCOV
698
        goto cleanup;
×
699
    }
700
    status = SIXEL_OK;
9✔
701

702
cleanup:
15✔
703
    if (decoded != NULL) {
16!
UNCOV
704
        sixel_allocator_free(work_allocator, decoded);
×
UNCOV
705
        decoded = NULL;
×
706
    }
707
    if (work_allocator != NULL) {
16!
708
        sixel_allocator_unref(work_allocator);
16✔
709
    }
1✔
710

711
    return status;
9✔
712
}
1✔
713

714
/* emacs Local Variables:      */
715
/* emacs mode: c               */
716
/* emacs tab-width: 4          */
717
/* emacs indent-tabs-mode: nil */
718
/* emacs c-basic-offset: 4     */
719
/* emacs End:                  */
720
/* vim: set expandtab ts=4 sts=4 sw=4 : */
721
/* 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