mirror of
https://gitlab.com/Theopse/fbi-i18n-zh.git
synced 2025-09-16 21:49:59 +08:00
upstream quirc update
This commit is contained in:
parent
417c345141
commit
7b744d9dcc
@ -127,30 +127,6 @@ const static struct galois_field gf256 = {
|
||||
* Polynomial operations
|
||||
*/
|
||||
|
||||
static void poly_mult(uint8_t *r, const uint8_t *a, const uint8_t *b,
|
||||
const struct galois_field *gf)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(r, 0, MAX_POLY);
|
||||
|
||||
for (i = 0; i < MAX_POLY; i++) {
|
||||
int j;
|
||||
|
||||
for (j = 0; j + i < MAX_POLY; j++) {
|
||||
uint8_t ca = a[i];
|
||||
uint8_t cb = b[j];
|
||||
|
||||
if (!(ca && cb))
|
||||
continue;
|
||||
|
||||
r[i + j] ^= gf->exp[(gf->log[ca] +
|
||||
gf->log[cb]) %
|
||||
gf->p];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void poly_add(uint8_t *dst, const uint8_t *src, uint8_t c,
|
||||
int shift, const struct galois_field *gf)
|
||||
{
|
||||
@ -274,7 +250,7 @@ static int block_syndromes(const uint8_t *data, int bs, int npar, uint8_t *s)
|
||||
continue;
|
||||
|
||||
s[i] ^= gf256_exp[((int)gf256_log[c] +
|
||||
(i + 1) * j) % 255];
|
||||
i * j) % 255];
|
||||
}
|
||||
|
||||
if (s[i])
|
||||
@ -284,9 +260,41 @@ static int block_syndromes(const uint8_t *data, int bs, int npar, uint8_t *s)
|
||||
return nonzero;
|
||||
}
|
||||
|
||||
static quirc_decode_error_t correct_block(uint8_t *data, const struct quirc_rs_params *ecc)
|
||||
static void eloc_poly(uint8_t *omega,
|
||||
const uint8_t *s, const uint8_t *sigma,
|
||||
int npar)
|
||||
{
|
||||
int npar = ecc->ce;
|
||||
int i;
|
||||
|
||||
memset(omega, 0, MAX_POLY);
|
||||
|
||||
for (i = 0; i < npar; i++) {
|
||||
const uint8_t a = sigma[i];
|
||||
const uint8_t log_a = gf256_log[a];
|
||||
int j;
|
||||
|
||||
if (!a)
|
||||
continue;
|
||||
|
||||
for (j = 0; j + 1 < MAX_POLY; j++) {
|
||||
const uint8_t b = s[j + 1];
|
||||
|
||||
if (i + j >= npar)
|
||||
break;
|
||||
|
||||
if (!b)
|
||||
continue;
|
||||
|
||||
omega[i + j] ^=
|
||||
gf256_exp[(log_a + gf256_log[b]) % 255];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static quirc_decode_error_t correct_block(uint8_t *data,
|
||||
const struct quirc_rs_params *ecc)
|
||||
{
|
||||
int npar = ecc->bs - ecc->dw;
|
||||
uint8_t s[MAX_POLY];
|
||||
uint8_t sigma[MAX_POLY];
|
||||
uint8_t sigma_deriv[MAX_POLY];
|
||||
@ -305,8 +313,7 @@ static quirc_decode_error_t correct_block(uint8_t *data, const struct quirc_rs_p
|
||||
sigma_deriv[i] = sigma[i + 1];
|
||||
|
||||
/* Compute error evaluator polynomial */
|
||||
poly_mult(omega, sigma, s, &gf256);
|
||||
memset(omega + npar, 0, MAX_POLY - npar);
|
||||
eloc_poly(omega, s, sigma, npar - 1);
|
||||
|
||||
/* Find error locations and magnitudes */
|
||||
for (i = 0; i < ecc->bs; i++) {
|
||||
@ -802,6 +809,29 @@ static quirc_decode_error_t decode_kanji(struct quirc_data *data,
|
||||
return QUIRC_SUCCESS;
|
||||
}
|
||||
|
||||
static quirc_decode_error_t decode_eci(struct quirc_data *data,
|
||||
struct datastream *ds)
|
||||
{
|
||||
if (bits_remaining(ds) < 8)
|
||||
return QUIRC_ERROR_DATA_UNDERFLOW;
|
||||
|
||||
data->eci = take_bits(ds, 8);
|
||||
|
||||
if ((data->eci & 0xc0) == 0x80) {
|
||||
if (bits_remaining(ds) < 8)
|
||||
return QUIRC_ERROR_DATA_UNDERFLOW;
|
||||
|
||||
data->eci = (data->eci << 8) | take_bits(ds, 8);
|
||||
} else if ((data->eci & 0xe0) == 0xc0) {
|
||||
if (bits_remaining(ds) < 16)
|
||||
return QUIRC_ERROR_DATA_UNDERFLOW;
|
||||
|
||||
data->eci = (data->eci << 16) | take_bits(ds, 16);
|
||||
}
|
||||
|
||||
return QUIRC_SUCCESS;
|
||||
}
|
||||
|
||||
static quirc_decode_error_t decode_payload(struct quirc_data *data,
|
||||
struct datastream *ds)
|
||||
{
|
||||
@ -826,6 +856,10 @@ static quirc_decode_error_t decode_payload(struct quirc_data *data,
|
||||
err = decode_kanji(data, ds);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
err = decode_eci(data, ds);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto done;
|
||||
}
|
||||
@ -833,7 +867,7 @@ static quirc_decode_error_t decode_payload(struct quirc_data *data,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (type > data->data_type)
|
||||
if (!(type & (type - 1)) && (type > data->data_type))
|
||||
data->data_type = type;
|
||||
}
|
||||
done:
|
||||
|
@ -121,59 +121,7 @@ static void perspective_unmap(const double *c,
|
||||
* Span-based floodfill routine
|
||||
*/
|
||||
|
||||
typedef struct fill_queue_node_s {
|
||||
int x;
|
||||
int y;
|
||||
|
||||
struct fill_queue_node_s* prev;
|
||||
struct fill_queue_node_s* next;
|
||||
} fill_queue_node;
|
||||
|
||||
typedef struct {
|
||||
fill_queue_node* last;
|
||||
} fill_queue;
|
||||
|
||||
static void fill_queue_init(fill_queue* queue) {
|
||||
queue->last = NULL;
|
||||
}
|
||||
|
||||
static int fill_queue_is_empty(fill_queue* queue) {
|
||||
return queue->last == NULL;
|
||||
}
|
||||
|
||||
static void fill_queue_push(fill_queue* queue, int x, int y) {
|
||||
fill_queue_node* node = (fill_queue_node*) calloc(1, sizeof(fill_queue_node));
|
||||
if(node == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
node->x = x;
|
||||
node->y = y;
|
||||
node->next = NULL;
|
||||
|
||||
if(queue->last == NULL) {
|
||||
node->prev = NULL;
|
||||
|
||||
queue->last = node;
|
||||
} else {
|
||||
node->prev = queue->last;
|
||||
|
||||
queue->last->next = node;
|
||||
queue->last = node;
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_queue_pop(fill_queue* queue, int* x, int* y) {
|
||||
fill_queue_node* node = queue->last;
|
||||
if(node != NULL) {
|
||||
queue->last = node->prev;
|
||||
|
||||
*x = node->x;
|
||||
*y = node->y;
|
||||
|
||||
free(node);
|
||||
}
|
||||
}
|
||||
#define FLOOD_FILL_MAX_DEPTH 4096
|
||||
|
||||
typedef void (*span_func_t)(void *user_data, int y, int left, int right);
|
||||
|
||||
@ -181,52 +129,44 @@ static void flood_fill_seed(struct quirc *q, int x, int y, int from, int to,
|
||||
span_func_t func, void *user_data,
|
||||
int depth)
|
||||
{
|
||||
fill_queue queue;
|
||||
fill_queue_init(&queue);
|
||||
fill_queue_push(&queue, x, y);
|
||||
int left = x;
|
||||
int right = x;
|
||||
int i;
|
||||
quirc_pixel_t *row = q->pixels + y * q->w;
|
||||
|
||||
while(!fill_queue_is_empty(&queue)) {
|
||||
int currX = 0;
|
||||
int currY = 0;
|
||||
fill_queue_pop(&queue, &currX, &currY);
|
||||
if (depth >= FLOOD_FILL_MAX_DEPTH)
|
||||
return;
|
||||
|
||||
int left = currX;
|
||||
int right = currX;
|
||||
int i;
|
||||
uint8_t *row = q->image + currY * q->w;
|
||||
while (left > 0 && row[left - 1] == from)
|
||||
left--;
|
||||
|
||||
if(row[currX] == to)
|
||||
continue;
|
||||
while (right < q->w - 1 && row[right + 1] == from)
|
||||
right++;
|
||||
|
||||
while (left > 0 && row[left - 1] == from)
|
||||
left--;
|
||||
/* Fill the extent */
|
||||
for (i = left; i <= right; i++)
|
||||
row[i] = to;
|
||||
|
||||
while (right < q->w - 1 && row[right + 1] == from)
|
||||
right++;
|
||||
if (func)
|
||||
func(user_data, y, left, right);
|
||||
|
||||
/* Seed new flood-fills */
|
||||
if (y > 0) {
|
||||
row = q->pixels + (y - 1) * q->w;
|
||||
|
||||
/* Fill the extent */
|
||||
for (i = left; i <= right; i++)
|
||||
row[i] = to;
|
||||
if (row[i] == from)
|
||||
flood_fill_seed(q, i, y - 1, from, to,
|
||||
func, user_data, depth + 1);
|
||||
}
|
||||
|
||||
if (func)
|
||||
func(user_data, currY, left, right);
|
||||
if (y < q->h - 1) {
|
||||
row = q->pixels + (y + 1) * q->w;
|
||||
|
||||
/* Seed new flood-fills */
|
||||
if (currY < q->h - 1) {
|
||||
row = q->image + (currY + 1) * q->w;
|
||||
|
||||
for (i = right; i >= left; i--)
|
||||
if (row[i] == from)
|
||||
fill_queue_push(&queue, i, currY + 1);
|
||||
}
|
||||
|
||||
if (currY > 0) {
|
||||
row = q->image + (currY - 1) * q->w;
|
||||
|
||||
for (i = right; i >= left; i--)
|
||||
if (row[i] == from)
|
||||
fill_queue_push(&queue, i, currY - 1);
|
||||
}
|
||||
for (i = left; i <= right; i++)
|
||||
if (row[i] == from)
|
||||
flood_fill_seed(q, i, y + 1, from, to,
|
||||
func, user_data, depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,7 +183,7 @@ static void threshold(struct quirc *q)
|
||||
int avg_w = 0;
|
||||
int avg_u = 0;
|
||||
int threshold_s = q->w / THRESHOLD_S_DEN;
|
||||
uint8_t *row = q->image;
|
||||
quirc_pixel_t *row = q->pixels;
|
||||
|
||||
for (y = 0; y < q->h; y++) {
|
||||
int row_average[q->w];
|
||||
@ -296,7 +236,7 @@ static int region_code(struct quirc *q, int x, int y)
|
||||
if (x < 0 || y < 0 || x >= q->w || y >= q->h)
|
||||
return -1;
|
||||
|
||||
pixel = q->image[y * q->w + x];
|
||||
pixel = q->pixels[y * q->w + x];
|
||||
|
||||
if (pixel >= QUIRC_PIXEL_REGION)
|
||||
return pixel;
|
||||
@ -475,7 +415,7 @@ static void test_capstone(struct quirc *q, int x, int y, int *pb)
|
||||
|
||||
static void finder_scan(struct quirc *q, int y)
|
||||
{
|
||||
uint8_t *row = q->image + y * q->w;
|
||||
quirc_pixel_t *row = q->pixels + y * q->w;
|
||||
int x;
|
||||
int last_color;
|
||||
int run_length = 0;
|
||||
@ -652,7 +592,7 @@ static int timing_scan(const struct quirc *q,
|
||||
if (y < 0 || y >= q->h || x < 0 || x >= q->w)
|
||||
break;
|
||||
|
||||
pixel = q->image[y * q->w + x];
|
||||
pixel = q->pixels[y * q->w + x];
|
||||
|
||||
if (pixel) {
|
||||
if (run_length >= 2)
|
||||
@ -730,7 +670,7 @@ static int read_cell(const struct quirc *q, int index, int x, int y)
|
||||
if (p.y < 0 || p.y >= q->h || p.x < 0 || p.x >= q->w)
|
||||
return 0;
|
||||
|
||||
return q->image[p.y * q->w + p.x] ? 1 : -1;
|
||||
return q->pixels[p.y * q->w + p.x] ? 1 : -1;
|
||||
}
|
||||
|
||||
static int fitness_cell(const struct quirc *q, int index, int x, int y)
|
||||
@ -749,7 +689,7 @@ static int fitness_cell(const struct quirc *q, int index, int x, int y)
|
||||
if (p.y < 0 || p.y >= q->h || p.x < 0 || p.x >= q->w)
|
||||
continue;
|
||||
|
||||
if (q->image[p.y * q->w + p.x])
|
||||
if (q->pixels[p.y * q->w + p.x])
|
||||
score++;
|
||||
else
|
||||
score--;
|
||||
@ -908,8 +848,8 @@ static void rotate_capstone(struct quirc_capstone *cap,
|
||||
{
|
||||
struct quirc_point copy[4];
|
||||
int j;
|
||||
int best = 0;
|
||||
int best_score = 0;
|
||||
int best;
|
||||
int best_score;
|
||||
|
||||
for (j = 0; j < 4; j++) {
|
||||
struct quirc_point *p = &cap->corners[j];
|
||||
@ -1126,6 +1066,20 @@ static void test_grouping(struct quirc *q, int i)
|
||||
test_neighbours(q, i, &hlist, &vlist);
|
||||
}
|
||||
|
||||
static void pixels_setup(struct quirc *q)
|
||||
{
|
||||
if (sizeof(*q->image) == sizeof(*q->pixels)) {
|
||||
q->pixels = (quirc_pixel_t *)q->image;
|
||||
} else {
|
||||
int x, y;
|
||||
for (y = 0; y < q->h; y++) {
|
||||
for (x = 0; x < q->w; x++) {
|
||||
q->pixels[y * q->w + x] = q->image[y * q->w + x];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *quirc_begin(struct quirc *q, int *w, int *h)
|
||||
{
|
||||
q->num_regions = QUIRC_PIXEL_REGION;
|
||||
@ -1144,6 +1098,7 @@ void quirc_end(struct quirc *q)
|
||||
{
|
||||
int i;
|
||||
|
||||
pixels_setup(q);
|
||||
threshold(q);
|
||||
|
||||
for (i = 0; i < q->h; i++)
|
||||
|
@ -38,6 +38,8 @@ void quirc_destroy(struct quirc *q)
|
||||
{
|
||||
if (q->image)
|
||||
free(q->image);
|
||||
if (sizeof(*q->image) != sizeof(*q->pixels))
|
||||
free(q->pixels);
|
||||
|
||||
free(q);
|
||||
}
|
||||
@ -49,6 +51,14 @@ int quirc_resize(struct quirc *q, int w, int h)
|
||||
if (!new_image)
|
||||
return -1;
|
||||
|
||||
if (sizeof(*q->image) != sizeof(*q->pixels)) {
|
||||
size_t new_size = w * h * sizeof(quirc_pixel_t);
|
||||
quirc_pixel_t *new_pixels = realloc(q->pixels, new_size);
|
||||
if (!new_pixels)
|
||||
return -1;
|
||||
q->pixels = new_pixels;
|
||||
}
|
||||
|
||||
q->image = new_image;
|
||||
q->w = w;
|
||||
q->h = h;
|
||||
|
@ -89,6 +89,23 @@ const char *quirc_strerror(quirc_decode_error_t err);
|
||||
#define QUIRC_DATA_TYPE_BYTE 4
|
||||
#define QUIRC_DATA_TYPE_KANJI 8
|
||||
|
||||
/* Common character encodings */
|
||||
#define QUIRC_ECI_ISO_8859_1 1
|
||||
#define QUIRC_ECI_IBM437 2
|
||||
#define QUIRC_ECI_ISO_8859_2 4
|
||||
#define QUIRC_ECI_ISO_8859_3 5
|
||||
#define QUIRC_ECI_ISO_8859_4 6
|
||||
#define QUIRC_ECI_ISO_8859_5 7
|
||||
#define QUIRC_ECI_ISO_8859_6 8
|
||||
#define QUIRC_ECI_ISO_8859_7 9
|
||||
#define QUIRC_ECI_ISO_8859_8 10
|
||||
#define QUIRC_ECI_ISO_8859_9 11
|
||||
#define QUIRC_ECI_WINDOWS_874 13
|
||||
#define QUIRC_ECI_ISO_8859_13 15
|
||||
#define QUIRC_ECI_ISO_8859_15 17
|
||||
#define QUIRC_ECI_SHIFT_JIS 20
|
||||
#define QUIRC_ECI_UTF_8 26
|
||||
|
||||
/* This structure is used to return information about detected QR codes
|
||||
* in the input image.
|
||||
*/
|
||||
@ -127,6 +144,9 @@ struct quirc_data {
|
||||
*/
|
||||
uint8_t payload[QUIRC_MAX_PAYLOAD];
|
||||
int payload_len;
|
||||
|
||||
/* ECI assignment number */
|
||||
uint32_t eci;
|
||||
};
|
||||
|
||||
/* Return the number of QR-codes identified in the last processed
|
||||
|
@ -23,12 +23,22 @@
|
||||
#define QUIRC_PIXEL_BLACK 1
|
||||
#define QUIRC_PIXEL_REGION 2
|
||||
|
||||
#ifndef QUIRC_MAX_REGIONS
|
||||
#define QUIRC_MAX_REGIONS 254
|
||||
#endif
|
||||
#define QUIRC_MAX_CAPSTONES 32
|
||||
#define QUIRC_MAX_GRIDS 8
|
||||
|
||||
#define QUIRC_PERSPECTIVE_PARAMS 8
|
||||
|
||||
#if QUIRC_MAX_REGIONS < UINT8_MAX
|
||||
typedef uint8_t quirc_pixel_t;
|
||||
#elif QUIRC_MAX_REGIONS < UINT16_MAX
|
||||
typedef uint16_t quirc_pixel_t;
|
||||
#else
|
||||
#error "QUIRC_MAX_REGIONS > 65534 is not supported"
|
||||
#endif
|
||||
|
||||
struct quirc_region {
|
||||
struct quirc_point seed;
|
||||
int count;
|
||||
@ -66,6 +76,7 @@ struct quirc_grid {
|
||||
|
||||
struct quirc {
|
||||
uint8_t *image;
|
||||
quirc_pixel_t *pixels;
|
||||
int w;
|
||||
int h;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user