LCOV - code coverage report
Current view: top level - src/decode - reader.c (source / functions) Coverage Total Hit
Test: lierre Coverage Report Lines: 81.9 % 243 199
Test Date: 2026-03-06 08:40:14 Functions: 100.0 % 13 13
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              :  * liblierre - reader.c
       3              :  *
       4              :  * This file is part of liblierre.
       5              :  *
       6              :  * Author: Go Kudo <zeriyoshi@gmail.com>
       7              :  * SPDX-License-Identifier: MIT
       8              :  */
       9              : 
      10              : #include <stdlib.h>
      11              : #include <string.h>
      12              : 
      13              : #include <lierre.h>
      14              : #include <lierre/portable.h>
      15              : #include <lierre/reader.h>
      16              : 
      17              : #include "../internal/decoder.h"
      18              : #include "../internal/image.h"
      19              : #include "../internal/memory.h"
      20              : 
      21              : #if LIERRE_USE_SIMD
      22              : #include "../internal/simd.h"
      23              : #endif
      24              : 
      25              : #include "../internal/structs.h"
      26              : 
      27              : #define LIERRE_IMAGE_MINIMIZE_MAX_SCALE 16
      28              : 
      29              : #define LIERRE_GRAY_WEIGHT_R       77
      30              : #define LIERRE_GRAY_WEIGHT_G       150
      31              : #define LIERRE_GRAY_WEIGHT_B       29
      32              : #define LIERRE_GRAY_SHIFT          8
      33              : #define LIERRE_MIN_QR_SIZE         21
      34              : #define LIERRE_PIXEL_VALUE_DEFAULT 255
      35              : 
      36          103 : static inline void lierre_rgb_to_gray(const uint8_t *src, uint8_t *dst, size_t pixel_count)
      37              : {
      38              : #if LIERRE_USE_SIMD && defined(LIERRE_SIMD_AVX2)
      39              :     __m256i r_weight, g_weight, b_weight;
      40              :     __m128i r0, g0, b0, r1, g1, gray8;
      41              :     __m256i r16, g16, b16, sum;
      42              :     size_t i, simd_count;
      43              :     const uint8_t *p;
      44              : 
      45          103 :     r_weight = _mm256_set1_epi16(LIERRE_GRAY_WEIGHT_R);
      46          103 :     g_weight = _mm256_set1_epi16(LIERRE_GRAY_WEIGHT_G);
      47          103 :     b_weight = _mm256_set1_epi16(LIERRE_GRAY_WEIGHT_B);
      48              : 
      49          103 :     simd_count = pixel_count & ~15ULL;
      50              : 
      51      7556667 :     for (i = 0; i < simd_count; i += 16) {
      52      7556564 :         p = src + i * 3;
      53              : 
      54     15113128 :         r0 = _mm_setr_epi8(p[0], p[3], p[6], p[9], p[12], p[15], p[18], p[21], p[24], p[27], p[30], p[33], p[36], p[39],
      55      7556564 :                            p[42], p[45]);
      56     15113128 :         g0 = _mm_setr_epi8(p[1], p[4], p[7], p[10], p[13], p[16], p[19], p[22], p[25], p[28], p[31], p[34], p[37],
      57      7556564 :                            p[40], p[43], p[46]);
      58      7556564 :         b0 = _mm_setr_epi8(p[2], p[5], p[8], p[11], p[14], p[17], p[20], p[23], p[26], p[29], p[32], p[35], p[38],
      59      7556564 :                            p[41], p[44], p[47]);
      60              : 
      61      7556564 :         r16 = _mm256_cvtepu8_epi16(r0);
      62      7556564 :         g16 = _mm256_cvtepu8_epi16(g0);
      63      7556564 :         b16 = _mm256_cvtepu8_epi16(b0);
      64              : 
      65     37782820 :         sum = _mm256_add_epi16(_mm256_mullo_epi16(r16, r_weight),
      66              :                                _mm256_add_epi16(_mm256_mullo_epi16(g16, g_weight), _mm256_mullo_epi16(b16, b_weight)));
      67      7556564 :         sum = _mm256_srli_epi16(sum, LIERRE_GRAY_SHIFT);
      68              : 
      69      7556564 :         r1 = _mm256_castsi256_si128(sum);
      70      7556564 :         g1 = _mm256_extracti128_si256(sum, 1);
      71      7556564 :         gray8 = _mm_packus_epi16(r1, g1);
      72              : 
      73      7556564 :         _mm_storeu_si128((__m128i *)(dst + i), gray8);
      74              :     }
      75              : 
      76          410 :     for (i = simd_count; i < pixel_count; i++) {
      77          307 :         p = src + i * 3;
      78          307 :         dst[i] = (uint8_t)((p[0] * LIERRE_GRAY_WEIGHT_R + p[1] * LIERRE_GRAY_WEIGHT_G + p[2] * LIERRE_GRAY_WEIGHT_B) >>
      79              :                            LIERRE_GRAY_SHIFT);
      80              :     }
      81              : #elif LIERRE_USE_SIMD && defined(LIERRE_SIMD_NEON)
      82              :     uint8x16x3_t rgb;
      83              :     uint16x8_t sum_lo, sum_hi;
      84              :     uint8x8_t gray_lo, gray_hi;
      85              :     uint8x16_t gray;
      86              :     size_t i, simd_count;
      87              : 
      88              :     simd_count = pixel_count & ~15ULL;
      89              : 
      90              :     for (i = 0; i < simd_count; i += 16) {
      91              :         rgb = vld3q_u8(src + i * 3);
      92              : 
      93              :         sum_lo = vmull_u8(vget_low_u8(rgb.val[0]), vdup_n_u8(LIERRE_GRAY_WEIGHT_R));
      94              :         sum_lo = vmlal_u8(sum_lo, vget_low_u8(rgb.val[1]), vdup_n_u8(LIERRE_GRAY_WEIGHT_G));
      95              :         sum_lo = vmlal_u8(sum_lo, vget_low_u8(rgb.val[2]), vdup_n_u8(LIERRE_GRAY_WEIGHT_B));
      96              : 
      97              :         sum_hi = vmull_u8(vget_high_u8(rgb.val[0]), vdup_n_u8(LIERRE_GRAY_WEIGHT_R));
      98              :         sum_hi = vmlal_u8(sum_hi, vget_high_u8(rgb.val[1]), vdup_n_u8(LIERRE_GRAY_WEIGHT_G));
      99              :         sum_hi = vmlal_u8(sum_hi, vget_high_u8(rgb.val[2]), vdup_n_u8(LIERRE_GRAY_WEIGHT_B));
     100              : 
     101              :         gray_lo = vshrn_n_u16(sum_lo, LIERRE_GRAY_SHIFT);
     102              :         gray_hi = vshrn_n_u16(sum_hi, LIERRE_GRAY_SHIFT);
     103              :         gray = vcombine_u8(gray_lo, gray_hi);
     104              : 
     105              :         vst1q_u8(dst + i, gray);
     106              :     }
     107              : 
     108              :     for (i = simd_count; i < pixel_count; i++) {
     109              :         const uint8_t *p = src + i * 3;
     110              :         dst[i] = (uint8_t)((p[0] * LIERRE_GRAY_WEIGHT_R + p[1] * LIERRE_GRAY_WEIGHT_G + p[2] * LIERRE_GRAY_WEIGHT_B) >>
     111              :                            LIERRE_GRAY_SHIFT);
     112              :     }
     113              : #elif LIERRE_USE_SIMD && defined(LIERRE_SIMD_WASM)
     114              :     v128_t r_weight, g_weight, b_weight;
     115              :     v128_t r0, g0, b0, r_lo, r_hi, g_lo, g_hi, b_lo, b_hi;
     116              :     v128_t sum_lo, sum_hi, gray;
     117              :     size_t i, simd_count;
     118              :     const uint8_t *p;
     119              :     uint8_t r_buf[16], g_buf[16], b_buf[16];
     120              :     size_t j;
     121              : 
     122              :     r_weight = wasm_i16x8_splat(LIERRE_GRAY_WEIGHT_R);
     123              :     g_weight = wasm_i16x8_splat(LIERRE_GRAY_WEIGHT_G);
     124              :     b_weight = wasm_i16x8_splat(LIERRE_GRAY_WEIGHT_B);
     125              : 
     126              :     simd_count = pixel_count & ~15ULL;
     127              : 
     128              :     for (i = 0; i < simd_count; i += 16) {
     129              :         p = src + i * 3;
     130              : 
     131              :         for (j = 0; j < 16; j++) {
     132              :             r_buf[j] = p[j * 3];
     133              :             g_buf[j] = p[j * 3 + 1];
     134              :             b_buf[j] = p[j * 3 + 2];
     135              :         }
     136              :         r0 = wasm_v128_load(r_buf);
     137              :         g0 = wasm_v128_load(g_buf);
     138              :         b0 = wasm_v128_load(b_buf);
     139              : 
     140              :         r_lo = wasm_u16x8_extend_low_u8x16(r0);
     141              :         r_hi = wasm_u16x8_extend_high_u8x16(r0);
     142              :         g_lo = wasm_u16x8_extend_low_u8x16(g0);
     143              :         g_hi = wasm_u16x8_extend_high_u8x16(g0);
     144              :         b_lo = wasm_u16x8_extend_low_u8x16(b0);
     145              :         b_hi = wasm_u16x8_extend_high_u8x16(b0);
     146              : 
     147              :         sum_lo = wasm_i16x8_add(wasm_i16x8_mul(r_lo, r_weight),
     148              :                                 wasm_i16x8_add(wasm_i16x8_mul(g_lo, g_weight), wasm_i16x8_mul(b_lo, b_weight)));
     149              :         sum_hi = wasm_i16x8_add(wasm_i16x8_mul(r_hi, r_weight),
     150              :                                 wasm_i16x8_add(wasm_i16x8_mul(g_hi, g_weight), wasm_i16x8_mul(b_hi, b_weight)));
     151              : 
     152              :         sum_lo = wasm_u16x8_shr(sum_lo, LIERRE_GRAY_SHIFT);
     153              :         sum_hi = wasm_u16x8_shr(sum_hi, LIERRE_GRAY_SHIFT);
     154              : 
     155              :         gray = wasm_u8x16_narrow_i16x8(sum_lo, sum_hi);
     156              : 
     157              :         wasm_v128_store(dst + i, gray);
     158              :     }
     159              : 
     160              :     for (i = simd_count; i < pixel_count; i++) {
     161              :         p = src + i * 3;
     162              :         dst[i] = (uint8_t)((p[0] * LIERRE_GRAY_WEIGHT_R + p[1] * LIERRE_GRAY_WEIGHT_G + p[2] * LIERRE_GRAY_WEIGHT_B) >>
     163              :                            LIERRE_GRAY_SHIFT);
     164              :     }
     165              : #else
     166              :     size_t i;
     167              :     const uint8_t *p;
     168              : 
     169              :     for (i = 0; i < pixel_count; i++) {
     170              :         p = src + i * 3;
     171              :         dst[i] = (uint8_t)((p[0] * LIERRE_GRAY_WEIGHT_R + p[1] * LIERRE_GRAY_WEIGHT_G + p[2] * LIERRE_GRAY_WEIGHT_B) >>
     172              :                            LIERRE_GRAY_SHIFT);
     173              :     }
     174              : #endif
     175          103 : }
     176              : 
     177          132 : extern lierre_error_t lierre_reader_param_init(lierre_reader_param_t *param)
     178              : {
     179          132 :     if (!param) {
     180            1 :         return LIERRE_ERROR_INVALID_PARAMS;
     181              :     }
     182              : 
     183          131 :     param->strategy_flags = LIERRE_READER_STRATEGY_NONE;
     184          131 :     param->rect = NULL;
     185              : 
     186          131 :     return LIERRE_ERROR_SUCCESS;
     187              : }
     188              : 
     189           82 : extern void lierre_reader_param_set_flag(lierre_reader_param_t *param, lierre_reader_strategy_flag_t flag)
     190              : {
     191           82 :     if (!param) {
     192            1 :         return;
     193              :     }
     194              : 
     195           81 :     param->strategy_flags |= flag;
     196              : }
     197              : 
     198           10 : extern void lierre_reader_param_set_rect(lierre_reader_param_t *param, const lierre_rect_t *rect)
     199              : {
     200           10 :     if (!param) {
     201            1 :         return;
     202              :     }
     203              : 
     204            9 :     param->rect = rect;
     205              : }
     206              : 
     207          126 : extern lierre_reader_t *lierre_reader_create(const lierre_reader_param_t *param)
     208              : {
     209              :     lierre_reader_t *reader;
     210              : 
     211          126 :     if (!param) {
     212            1 :         return NULL;
     213              :     }
     214              : 
     215          125 :     reader = lmalloc(sizeof(lierre_reader_t));
     216          125 :     if (!reader) {
     217            0 :         return NULL;
     218              :     }
     219              : 
     220          125 :     reader->data = NULL;
     221          125 :     reader->param = lmalloc(sizeof(lierre_reader_param_t));
     222          125 :     if (!reader->param) {
     223            0 :         lfree(reader);
     224            0 :         return NULL;
     225              :     }
     226              : 
     227          125 :     lmemcpy(reader->param, param, sizeof(lierre_reader_param_t));
     228              : 
     229          125 :     return reader;
     230              : }
     231              : 
     232          126 : extern void lierre_reader_destroy(lierre_reader_t *reader)
     233              : {
     234          126 :     if (!reader) {
     235            1 :         return;
     236              :     }
     237              : 
     238          125 :     if (reader->param) {
     239          125 :         lfree(reader->param);
     240              :     }
     241              : 
     242          125 :     lfree(reader);
     243              : }
     244              : 
     245          110 : extern void lierre_reader_set_data(lierre_reader_t *reader, lierre_rgb_data_t *data)
     246              : {
     247          110 :     if (!reader) {
     248            1 :         return;
     249              :     }
     250              : 
     251          109 :     reader->data = data;
     252              : }
     253              : 
     254          112 : extern lierre_error_t lierre_reader_read(lierre_reader_t *reader, lierre_reader_result_t **result)
     255              : {
     256              :     const uint8_t *pixel;
     257              :     lierre_reader_result_t *res;
     258              :     decoder_t *decoder;
     259              :     decoder_result_t *dec_result;
     260              :     lierre_error_t err;
     261              :     uint32_t num_threads, scale, sum, dy, dx, scale_shift, temp;
     262              :     uint8_t *gray_data, *scaled_gray, r, g, b, gray;
     263              :     int32_t rect_w, rect_h;
     264              :     size_t i, j, start_x, start_y, width, height, src_x, src_y, src_idx, sw, sh, sy, sx, gx, gy;
     265              :     bool use_mt, use_quirc_grayscale;
     266              : 
     267          112 :     if (!reader || !result || !reader->data || !reader->data->data) {
     268            3 :         return LIERRE_ERROR_INVALID_PARAMS;
     269              :     }
     270              : 
     271          109 :     dec_result = lmalloc(sizeof(decoder_result_t));
     272          109 :     if (!dec_result) {
     273            0 :         return LIERRE_ERROR_DATA_OVERFLOW;
     274              :     }
     275              : 
     276          109 :     use_mt = (reader->param->strategy_flags & LIERRE_READER_STRATEGY_MT) != 0;
     277          109 :     num_threads = use_mt ? lierre_get_cpu_count() : 1;
     278              : 
     279          109 :     start_x = 0;
     280          109 :     start_y = 0;
     281          109 :     width = reader->data->width;
     282          109 :     height = reader->data->height;
     283              : 
     284          109 :     if ((reader->param->strategy_flags & LIERRE_READER_STRATEGY_USE_RECT) && reader->param->rect) {
     285            6 :         start_x = reader->param->rect->origin.x;
     286            6 :         start_y = reader->param->rect->origin.y;
     287            6 :         width = reader->param->rect->size.width;
     288            6 :         height = reader->param->rect->size.height;
     289            6 :         if (width == 0 || height == 0 || width > SIZE_MAX / height) {
     290            0 :             lfree(dec_result);
     291            0 :             return LIERRE_ERROR_INVALID_PARAMS;
     292              :         }
     293              :     }
     294              : 
     295          109 :     gray_data = lmalloc(width * height);
     296          109 :     if (!gray_data) {
     297            0 :         lfree(dec_result);
     298            0 :         return LIERRE_ERROR_DATA_OVERFLOW;
     299              :     }
     300              : 
     301          109 :     if (start_x == 0 && start_y == 0 && width == reader->data->width && height == reader->data->height) {
     302          103 :         lierre_rgb_to_gray(reader->data->data, gray_data, width * height);
     303              :     } else {
     304         1106 :         for (i = 0; i < height; i++) {
     305       531100 :             for (j = 0; j < width; j++) {
     306       530000 :                 src_x = start_x + j;
     307       530000 :                 src_y = start_y + i;
     308       530000 :                 if (src_x >= reader->data->width || src_y >= reader->data->height) {
     309            0 :                     gray_data[i * width + j] = LIERRE_PIXEL_VALUE_DEFAULT;
     310            0 :                     continue;
     311              :                 }
     312       530000 :                 src_idx = (src_y * reader->data->width + src_x) * 3;
     313       530000 :                 r = reader->data->data[src_idx];
     314       530000 :                 g = reader->data->data[src_idx + 1];
     315       530000 :                 b = reader->data->data[src_idx + 2];
     316       530000 :                 gray = (uint8_t)((r * LIERRE_GRAY_WEIGHT_R + g * LIERRE_GRAY_WEIGHT_G + b * LIERRE_GRAY_WEIGHT_B) >>
     317              :                                  LIERRE_GRAY_SHIFT);
     318       530000 :                 gray_data[i * width + j] = gray;
     319              :             }
     320              :         }
     321              :     }
     322              : 
     323          109 :     if (reader->param->strategy_flags & LIERRE_READER_STRATEGY_DENOISE) {
     324            4 :         if (use_mt) {
     325            2 :             image_denoise_mt(gray_data, width, height, num_threads);
     326              :         } else {
     327            2 :             image_denoise(gray_data, width, height);
     328              :         }
     329              :     }
     330              : 
     331          109 :     if (reader->param->strategy_flags & LIERRE_READER_STRATEGY_BRIGHTNESS_NORMALIZE) {
     332            1 :         image_brightness_normalize(gray_data, width, height);
     333              :     }
     334              : 
     335          109 :     if (reader->param->strategy_flags & LIERRE_READER_STRATEGY_CONTRAST_NORMALIZE) {
     336            1 :         image_contrast_normalize(gray_data, width, height);
     337              :     }
     338              : 
     339          109 :     if (reader->param->strategy_flags & LIERRE_READER_STRATEGY_SHARPENING) {
     340            3 :         if (use_mt) {
     341            2 :             image_sharpen_mt(gray_data, width, height, num_threads);
     342              :         } else {
     343            1 :             image_sharpen(gray_data, width, height);
     344              :         }
     345              :     }
     346              : 
     347          109 :     decoder = lierre_decoder_create();
     348          109 :     if (!decoder) {
     349            0 :         lfree(gray_data);
     350            0 :         lfree(dec_result);
     351              : 
     352            0 :         return LIERRE_ERROR_DATA_OVERFLOW;
     353              :     }
     354              : 
     355          109 :     dec_result->count = 0;
     356              : 
     357          109 :     if (reader->param->strategy_flags & LIERRE_READER_STRATEGY_MINIMIZE) {
     358            5 :         use_quirc_grayscale = (reader->param->strategy_flags & LIERRE_READER_STRATEGY_GRAYSCALE) != 0;
     359              : 
     360           19 :         for (scale = 1; scale <= LIERRE_IMAGE_MINIMIZE_MAX_SCALE; scale *= 2) {
     361           19 :             sw = width / scale;
     362           19 :             sh = height / scale;
     363              : 
     364           19 :             if (sw < LIERRE_MIN_QR_SIZE || sh < LIERRE_MIN_QR_SIZE) {
     365              :                 break;
     366              :             }
     367              : 
     368           17 :             scale_shift = 0;
     369           17 :             temp = scale;
     370           38 :             while (temp > 1) {
     371           21 :                 temp >>= 1;
     372           21 :                 scale_shift++;
     373              :             }
     374           17 :             scale_shift *= 2;
     375              : 
     376           17 :             scaled_gray = lmalloc(sw * sh);
     377           17 :             if (!scaled_gray) {
     378            0 :                 break;
     379              :             }
     380              : 
     381           17 :             if (use_quirc_grayscale) {
     382            0 :                 for (sy = 0; sy < sh; sy++) {
     383            0 :                     for (sx = 0; sx < sw; sx++) {
     384            0 :                         sum = 0;
     385            0 :                         for (dy = 0; dy < scale; dy++) {
     386            0 :                             for (dx = 0; dx < scale; dx++) {
     387            0 :                                 src_x = start_x + sx * scale + dx;
     388            0 :                                 src_y = start_y + sy * scale + dy;
     389            0 :                                 if (src_x >= reader->data->width || src_y >= reader->data->height) {
     390            0 :                                     sum += LIERRE_PIXEL_VALUE_DEFAULT;
     391            0 :                                     continue;
     392              :                                 }
     393            0 :                                 src_idx = (src_y * reader->data->width + src_x) * 3;
     394            0 :                                 pixel = reader->data->data + src_idx;
     395            0 :                                 sum += (pixel[0] * LIERRE_GRAY_WEIGHT_R + pixel[1] * LIERRE_GRAY_WEIGHT_G +
     396            0 :                                         pixel[2] * LIERRE_GRAY_WEIGHT_B) >>
     397              :                                        LIERRE_GRAY_SHIFT;
     398              :                             }
     399              :                         }
     400            0 :                         scaled_gray[sy * sw + sx] = (uint8_t)(sum >> scale_shift);
     401              :                     }
     402              :                 }
     403              :             } else {
     404         6437 :                 for (sy = 0; sy < sh; sy++) {
     405      8277470 :                     for (sx = 0; sx < sw; sx++) {
     406      8271050 :                         sum = 0;
     407     19307450 :                         for (dy = 0; dy < scale; dy++) {
     408     30018800 :                             for (dx = 0; dx < scale; dx++) {
     409     18982400 :                                 gx = sx * scale + dx;
     410     18982400 :                                 gy = sy * scale + dy;
     411     18982400 :                                 if (gx < width && gy < height) {
     412     18982400 :                                     sum += gray_data[gy * width + gx];
     413              :                                 } else {
     414            0 :                                     sum += LIERRE_PIXEL_VALUE_DEFAULT;
     415              :                                 }
     416              :                             }
     417              :                         }
     418      8271050 :                         scaled_gray[sy * sw + sx] = (uint8_t)(sum >> scale_shift);
     419              :                     }
     420              :                 }
     421              :             }
     422              : 
     423           17 :             if (use_mt) {
     424              :                 err =
     425            7 :                     lierre_decoder_process_mt(decoder, scaled_gray, (int32_t)sw, (int32_t)sh, dec_result, num_threads);
     426              :             } else {
     427           10 :                 err = lierre_decoder_process(decoder, scaled_gray, (int32_t)sw, (int32_t)sh, dec_result);
     428              :             }
     429              : 
     430           17 :             lfree(scaled_gray);
     431              : 
     432           17 :             if (err == LIERRE_ERROR_SUCCESS && dec_result->count > 0) {
     433            3 :                 break;
     434              :             }
     435              :         }
     436              : 
     437            5 :         lfree(gray_data);
     438              :     } else {
     439          104 :         if (use_mt) {
     440              :             err =
     441           41 :                 lierre_decoder_process_mt(decoder, gray_data, (int32_t)width, (int32_t)height, dec_result, num_threads);
     442              :         } else {
     443           63 :             err = lierre_decoder_process(decoder, gray_data, (int32_t)width, (int32_t)height, dec_result);
     444              :         }
     445          104 :         lfree(gray_data);
     446              : 
     447          104 :         if (err != LIERRE_ERROR_SUCCESS) {
     448            0 :             lfree(dec_result);
     449            0 :             lierre_decoder_destroy(decoder);
     450              : 
     451            0 :             return err;
     452              :         }
     453              :     }
     454              : 
     455          109 :     res = lmalloc(sizeof(lierre_reader_result_t));
     456          109 :     if (!res) {
     457            0 :         lfree(dec_result);
     458            0 :         lierre_decoder_destroy(decoder);
     459              : 
     460            0 :         return LIERRE_ERROR_DATA_OVERFLOW;
     461              :     }
     462              : 
     463          109 :     res->num_qr_codes = dec_result->count;
     464          109 :     res->qr_code_rects = NULL;
     465          109 :     res->qr_code_datas = NULL;
     466          109 :     res->qr_code_data_sizes = NULL;
     467              : 
     468          109 :     if (dec_result->count > 0) {
     469          101 :         res->qr_code_rects = lcalloc(dec_result->count, sizeof(lierre_rect_t));
     470          101 :         res->qr_code_datas = lcalloc(dec_result->count, sizeof(uint8_t *));
     471          101 :         res->qr_code_data_sizes = lcalloc(dec_result->count, sizeof(size_t));
     472              : 
     473          101 :         if (!res->qr_code_rects || !res->qr_code_datas || !res->qr_code_data_sizes) {
     474            0 :             lfree(res->qr_code_rects);
     475            0 :             lfree(res->qr_code_datas);
     476            0 :             lfree(res->qr_code_data_sizes);
     477            0 :             lfree(res);
     478            0 :             lfree(dec_result);
     479            0 :             lierre_decoder_destroy(decoder);
     480              : 
     481            0 :             return LIERRE_ERROR_DATA_OVERFLOW;
     482              :         }
     483              : 
     484          205 :         for (i = 0; i < dec_result->count; i++) {
     485          104 :             res->qr_code_rects[i].origin.x = start_x + dec_result->codes[i].corners[0].x;
     486          104 :             res->qr_code_rects[i].origin.y = start_y + dec_result->codes[i].corners[0].y;
     487              : 
     488          104 :             rect_w = dec_result->codes[i].corners[2].x - dec_result->codes[i].corners[0].x;
     489          104 :             rect_h = dec_result->codes[i].corners[2].y - dec_result->codes[i].corners[0].y;
     490          104 :             res->qr_code_rects[i].size.width = (rect_w > 0) ? (size_t)rect_w : 0;
     491          104 :             res->qr_code_rects[i].size.height = (rect_h > 0) ? (size_t)rect_h : 0;
     492              : 
     493          104 :             res->qr_code_data_sizes[i] = (size_t)dec_result->codes[i].payload_len;
     494          104 :             res->qr_code_datas[i] = lmalloc(res->qr_code_data_sizes[i] + 1);
     495          104 :             if (res->qr_code_datas[i]) {
     496          104 :                 lmemcpy(res->qr_code_datas[i], dec_result->codes[i].payload, res->qr_code_data_sizes[i]);
     497          104 :                 res->qr_code_datas[i][res->qr_code_data_sizes[i]] = '\0';
     498              :             }
     499              :         }
     500              :     }
     501              : 
     502          109 :     lfree(dec_result);
     503          109 :     lierre_decoder_destroy(decoder);
     504          109 :     *result = res;
     505              : 
     506          109 :     return LIERRE_ERROR_SUCCESS;
     507              : }
     508              : 
     509          110 : extern void lierre_reader_result_destroy(lierre_reader_result_t *result)
     510              : {
     511              :     uint32_t i;
     512              : 
     513          110 :     if (!result) {
     514            1 :         return;
     515              :     }
     516              : 
     517          109 :     if (result->qr_code_datas) {
     518          205 :         for (i = 0; i < result->num_qr_codes; i++) {
     519          104 :             if (result->qr_code_datas[i]) {
     520          104 :                 lfree(result->qr_code_datas[i]);
     521              :             }
     522              :         }
     523          101 :         lfree(result->qr_code_datas);
     524              :     }
     525              : 
     526          109 :     if (result->qr_code_rects) {
     527          101 :         lfree(result->qr_code_rects);
     528              :     }
     529              : 
     530          109 :     if (result->qr_code_data_sizes) {
     531          101 :         lfree(result->qr_code_data_sizes);
     532              :     }
     533              : 
     534          109 :     lfree(result);
     535              : }
     536              : 
     537          105 : extern uint32_t lierre_reader_result_get_num_qr_codes(const lierre_reader_result_t *result)
     538              : {
     539          105 :     if (!result) {
     540            1 :         return 0;
     541              :     }
     542              : 
     543          104 :     return result->num_qr_codes;
     544              : }
     545              : 
     546            1 : extern const lierre_rect_t *lierre_reader_result_get_qr_code_rect(const lierre_reader_result_t *result, uint32_t index)
     547              : {
     548            1 :     if (!result || index >= result->num_qr_codes || !result->qr_code_rects) {
     549            1 :         return NULL;
     550              :     }
     551              : 
     552            0 :     return &result->qr_code_rects[index];
     553              : }
     554              : 
     555          102 : extern const uint8_t *lierre_reader_result_get_qr_code_data(const lierre_reader_result_t *result, uint32_t index)
     556              : {
     557          102 :     if (!result || index >= result->num_qr_codes || !result->qr_code_datas) {
     558            1 :         return NULL;
     559              :     }
     560              : 
     561          101 :     return result->qr_code_datas[index];
     562              : }
     563              : 
     564          102 : extern size_t lierre_reader_result_get_qr_code_data_size(const lierre_reader_result_t *result, uint32_t index)
     565              : {
     566          102 :     if (!result || index >= result->num_qr_codes || !result->qr_code_data_sizes) {
     567            1 :         return 0;
     568              :     }
     569              : 
     570          101 :     return result->qr_code_data_sizes[index];
     571              : }
        

Generated by: LCOV version 2.0-1