File nand_grading_support.patch of Package zbar
diff --git a/include/zbar.h b/include/zbar.h
index 66281c1..cb68b48 100644
--- a/include/zbar.h
+++ b/include/zbar.h
@@ -364,6 +364,23 @@ extern zbar_error_t _zbar_get_error_code(const void *object);
/*@}*/
+typedef struct decodeErrorsInfo_struct {
+ int errors[81];
+ int maxCorrectableErrors[81];
+ int checkedBlocks;
+ int totalBlocks;
+ int readError;
+} decodeErrorsInfo;
+typedef struct codeStructureInfo_struct {
+ // int numElems[81][2];
+ int (*numElems)[2];
+ // int blocks[81][2][153][8][2];
+ int (*blocks)[2][153][8][2];
+ int numBlocks;
+ int codeSize;
+ int valid;
+} codeStructureInfo;
+
struct zbar_symbol_s;
typedef struct zbar_symbol_s zbar_symbol_t;
@@ -1567,6 +1584,10 @@ extern unsigned zbar_scanner_get_edge(const zbar_scanner_t *scn,
/** retrieve last scanned color. */
extern zbar_color_t zbar_scanner_get_color(const zbar_scanner_t *scanner);
+extern float zbar_uec(const zbar_symbol_t* sym);
+extern codeStructureInfo* zbar_structure(const zbar_symbol_t* sym);
+extern int zbar_size(const zbar_symbol_t* sym);
+
/*@}*/
#ifdef __cplusplus
diff --git a/include/zbar/Symbol.h b/include/zbar/Symbol.h
index f3a5668..c011c86 100644
--- a/include/zbar/Symbol.h
+++ b/include/zbar/Symbol.h
@@ -35,6 +35,8 @@
#include <stdlib.h>
#include <string>
+#include <vector>
+
namespace zbar
{
class SymbolIterator;
@@ -398,6 +400,45 @@ public:
return (zbar_symbol_xml(_sym, (char **)&_xmlbuf, (unsigned *)&_xmllen));
}
+ float uec() const
+ {
+ return zbar_uec(_sym);
+ }
+ std::vector< std::vector< std::vector< std::vector< std::vector<int> > > > > structure() const
+ {
+ std::vector< std::vector< std::vector< std::vector< std::vector<int> > > > > ret;
+ if (_type != ZBAR_QRCODE) {
+ return ret;
+ }
+ codeStructureInfo* res = zbar_structure(_sym);
+ if (!res->valid) {
+ return ret;
+ }
+ for (int block = 0; block < res->numBlocks; ++block) {
+ std::vector< std::vector< std::vector< std::vector<int> > > > t4;
+ for (int type = 0; type < 2; ++type) {
+ std::vector< std::vector< std::vector<int> > > t3;
+ for (int sym = 0; sym < res->numElems[block][type]; ++sym) {
+ std::vector< std::vector<int> > t2;
+ for (int bit = 0; bit < 8; ++bit) {
+ std::vector<int> t1;
+ t1.push_back(res->blocks[block][type][sym][bit][0]);
+ t1.push_back(res->blocks[block][type][sym][bit][1]);
+ t2.push_back( std::move(t1) );
+ }
+ t3.push_back( std::move(t2) );
+ }
+ t4.push_back( std::move(t3) );
+ }
+ ret.push_back( std::move(t4) );
+ }
+ return ret;
+ }
+ int size() const
+ {
+ return zbar_size(_sym);
+ }
+
protected:
/// (re)initialize Symbol from C symbol object.
void init(const zbar_symbol_t *sym = NULL)
diff --git a/zbar/img_scanner.c b/zbar/img_scanner.c
index 3e235d1..71fcfc5 100644
--- a/zbar/img_scanner.c
+++ b/zbar/img_scanner.c
@@ -169,6 +169,11 @@ void _zbar_image_scanner_recycle_syms(zbar_image_scanner_t *iscn,
free(sym->data);
sym->data = NULL;
sym->data_alloc = 0;
+
+ sym->str.valid = 0;
+ if (sym->str.numElems) {free(sym->str.numElems); sym->str.numElems = NULL;}
+ if (sym->str.blocks) {free(sym->str.blocks); sym->str.blocks = NULL;}
+
i = 0;
}
bucket = &iscn->recycle[i];
@@ -253,6 +258,12 @@ inline zbar_symbol_t *_zbar_image_scanner_alloc_sym(zbar_image_scanner_t *iscn,
sym->orient = ZBAR_ORIENT_UNKNOWN;
sym->cache_count = 0;
sym->time = iscn->time;
+
+ sym->uec.readError = 1;
+ sym->str.valid = 0;
+ sym->str.numElems = malloc(sizeof(*sym->str.numElems) * 81);
+ sym->str.blocks = malloc(sizeof(*sym->str.blocks) * 81);
+
assert(!sym->syms);
if (datalen > 0) {
diff --git a/zbar/qrcode/qrdec.c b/zbar/qrcode/qrdec.c
index 905336a..27f2398 100644
--- a/zbar/qrcode/qrdec.c
+++ b/zbar/qrcode/qrdec.c
@@ -3289,7 +3289,8 @@ static void qr_sampling_grid_sample(const qr_sampling_grid *_grid,
static void qr_samples_unpack(unsigned char **_blocks, int _nblocks,
int _nshort_data, int _nshort_blocks,
const unsigned *_data_bits,
- const unsigned *_fp_mask, int _dim)
+ const unsigned *_fp_mask, int _dim,
+ codeStructureInfo *_info)
{
unsigned bits;
int biti;
@@ -3298,6 +3299,23 @@ static void qr_samples_unpack(unsigned char **_blocks, int _nblocks,
int blockj;
int i;
int j;
+
+ int numTotalDataSyms;
+ int currInsSyms;
+ int storage[9][2];
+ _info->codeSize = _dim;
+ _info->numBlocks = _nblocks;
+ if (_info->numElems) {free(_info->numElems);}
+ _info->numElems = malloc(sizeof(*_info->numElems) * _nblocks);
+ if (_info->blocks) {free(_info->blocks);}
+ _info->blocks = malloc(sizeof(*_info->blocks) * _nblocks);
+ for (int ij = 0; ij < _nblocks; ++ij) {
+ _info->numElems[ij][0] = 0;
+ _info->numElems[ij][1] = 0;
+ }
+ numTotalDataSyms = _nshort_blocks * _nshort_data + (_nblocks - _nshort_blocks) * (_nshort_data + 1);
+ currInsSyms = 0;
+
stride = _dim + QR_INT_BITS - 1 >> QR_INT_LOGBITS;
/*If _all_ the blocks are short, don't skip anything (see below).*/
if (_nshort_blocks >= _nblocks)
@@ -3323,16 +3341,36 @@ static void qr_samples_unpack(unsigned char **_blocks, int _nblocks,
/*Pull a bit from the right column.*/
if (!(fp_mask1 >> nbits & 1)) {
bits = bits << 1 | data1 >> nbits & 1;
+
+ storage[biti][0] = j;
+ storage[biti][1] = nbits + QR_INT_BITS * i;
+
biti++;
}
/*Pull a bit from the left column.*/
if (!(fp_mask2 >> nbits & 1)) {
bits = bits << 1 | data2 >> nbits & 1;
+
+ storage[biti][0] = j - 1;
+ storage[biti][1] = nbits + QR_INT_BITS * i;
+
biti++;
}
/*If we finished a byte, drop it in a block.*/
if (biti >= 8) {
+
biti -= 8;
+
+ for (int bi = 0; bi < 8; ++bi) {
+ _info->blocks[blocki][ ((currInsSyms >= numTotalDataSyms) ? 1 : 0) ][ _info->numElems[blocki][ ((currInsSyms >= numTotalDataSyms) ? 1 : 0) ] ][bi][0] = storage[bi][0];
+ _info->blocks[blocki][ ((currInsSyms >= numTotalDataSyms) ? 1 : 0) ][ _info->numElems[blocki][ ((currInsSyms >= numTotalDataSyms) ? 1 : 0) ] ][bi][1] = storage[bi][1];
+ }
+ if (biti > 0) {
+ storage[0][0] = storage[8][0];
+ storage[0][1] = storage[8][1];
+ }
+ (++currInsSyms > numTotalDataSyms) ? (_info->numElems[blocki][1]++) : (_info->numElems[blocki][0]++);
+
*_blocks[blocki++]++ = (unsigned char)(bits >> biti);
/*For whatever reason, the long blocks are at the _end_ of the list,
instead of the beginning.
@@ -3356,15 +3394,25 @@ static void qr_samples_unpack(unsigned char **_blocks, int _nblocks,
/*Scan down a pair of columns.*/
l = j * stride;
for (i = 0; i < stride; i++) {
+
+ int maxnbits;
+
data1 = _data_bits[l + i];
fp_mask1 = _fp_mask[l + i];
data2 = _data_bits[l + i - stride];
fp_mask2 = _fp_mask[l + i - stride];
nbits = QR_MINI(_dim - (i << QR_INT_LOGBITS), QR_INT_BITS);
+
+ maxnbits = nbits - 1;
+
while (nbits-- > 0) {
/*Pull a bit from the right column.*/
if (!(fp_mask1 & 1)) {
bits = bits << 1 | data1 & 1;
+
+ storage[biti][0] = j;
+ storage[biti][1] = (maxnbits - nbits) + QR_INT_BITS * i;
+
biti++;
}
data1 >>= 1;
@@ -3372,13 +3420,29 @@ static void qr_samples_unpack(unsigned char **_blocks, int _nblocks,
/*Pull a bit from the left column.*/
if (!(fp_mask2 & 1)) {
bits = bits << 1 | data2 & 1;
+
+ storage[biti][0] = j - 1;
+ storage[biti][1] = (maxnbits - nbits) + QR_INT_BITS * i;
+
biti++;
}
data2 >>= 1;
fp_mask2 >>= 1;
/*If we finished a byte, drop it in a block.*/
if (biti >= 8) {
+
biti -= 8;
+
+ for (int bi = 0; bi < 8; ++bi) {
+ _info->blocks[blocki][ ((currInsSyms >= numTotalDataSyms) ? 1 : 0) ][ _info->numElems[blocki][ ((currInsSyms >= numTotalDataSyms) ? 1 : 0) ] ][bi][0] = storage[bi][0];
+ _info->blocks[blocki][ ((currInsSyms >= numTotalDataSyms) ? 1 : 0) ][ _info->numElems[blocki][ ((currInsSyms >= numTotalDataSyms) ? 1 : 0) ] ][bi][1] = storage[bi][1];
+ }
+ if (biti > 0) {
+ storage[0][0] = storage[8][0];
+ storage[0][1] = storage[8][1];
+ }
+ (++currInsSyms > numTotalDataSyms) ? (_info->numElems[blocki][1]++) : (_info->numElems[blocki][0]++);
+
*_blocks[blocki++]++ = (unsigned char)(bits >> biti);
/*See comments on the "up" loop for the reason behind this mess.*/
if (blocki >= _nblocks)
@@ -3387,6 +3451,9 @@ static void qr_samples_unpack(unsigned char **_blocks, int _nblocks,
}
}
}
+
+ _info->valid = 1;
+
}
/*Bit reading code blatantly stolen^W^Wadapted from libogg/libtheora (because
@@ -3745,6 +3812,10 @@ static void qr_code_data_clear(qr_code_data *_qrdata)
}
}
free(_qrdata->entries);
+
+ if (_qrdata->str.numElems) {free(_qrdata->str.numElems); _qrdata->str.numElems = NULL;}
+ if (_qrdata->str.blocks) {free(_qrdata->str.blocks); _qrdata->str.blocks = NULL;}
+
}
void qr_code_data_list_init(qr_code_data_list *_qrlist)
@@ -3909,7 +3980,7 @@ static int qr_code_decode(qr_code_data *_qrdata, const rs_gf256 *_gf,
for (i = 1; i < nblocks; i++)
blocks[i] = blocks[i - 1] + block_sz + (i > nshort_blocks);
qr_samples_unpack(blocks, nblocks, block_sz - npar, nshort_blocks,
- data_bits, grid.fpmask, dim);
+ data_bits, grid.fpmask, dim, &_qrdata->str);
qr_sampling_grid_clear(&grid);
free(blocks);
free(data_bits);
@@ -3917,6 +3988,10 @@ static int qr_code_decode(qr_code_data *_qrdata, const rs_gf256 *_gf,
ndata = 0;
ncodewords = 0;
ret = 0;
+
+ _qrdata->uec.checkedBlocks = 0;
+ _qrdata->uec.totalBlocks = nblocks;
+
for (i = 0; i < nblocks; i++) {
int block_szi;
int ndatai;
@@ -3925,6 +4000,19 @@ static int qr_code_decode(qr_code_data *_qrdata, const rs_gf256 *_gf,
NULL, 0);
zprintf(1, "Number of errors corrected: %i%s\n", ret,
ret < 0 ? " (data irrecoverable)" : "");
+
+ _qrdata->uec.errors[i] = ret;
+ if (_version == 1) {
+ _qrdata->uec.maxCorrectableErrors[i] = (ecc_level + 1) << 1;
+ }
+ else if (_version == 2 && ecc_level == 0) {
+ _qrdata->uec.maxCorrectableErrors[i] = (npar - 1) >> 1;
+ }
+ else {
+ _qrdata->uec.maxCorrectableErrors[i] = npar >> 1;
+ }
+ _qrdata->uec.checkedBlocks += 1;
+
/*For version 1 symbols and version 2-L and 3-L symbols, we aren't allowed
to use all the parity bytes for correction.
They are instead used to improve detection.
@@ -3951,9 +4039,19 @@ static int qr_code_decode(qr_code_data *_qrdata, const rs_gf256 *_gf,
API support for that; a mode ignoring ECC errors might also be useful.*/
if (ret < 0)
qr_code_data_clear(_qrdata);
+
+ else
+ _qrdata->uec.readError = 0;
+
_qrdata->version = _version;
_qrdata->ecc_level = ecc_level;
}
+
+ else {
+ if (_qrdata->str.numElems) {free(_qrdata->str.numElems); _qrdata->str.numElems = NULL;}
+ if (_qrdata->str.blocks) {free(_qrdata->str.blocks); _qrdata->str.blocks = NULL;}
+ }
+
free(block_data);
return ret;
}
@@ -4247,6 +4345,12 @@ void qr_reader_match_centers(qr_reader *_reader, qr_code_data_list *_qrlist,
if (!mark[k]) {
qr_finder_center *c[3];
qr_code_data qrdata;
+
+ qrdata.uec.readError = 1;
+ qrdata.str.valid = 0;
+ qrdata.str.numElems = NULL;
+ qrdata.str.blocks = NULL;
+
int version;
c[0] = _centers + i;
c[1] = _centers + j;
diff --git a/zbar/qrcode/qrdec.h b/zbar/qrcode/qrdec.h
index 40cb204..5192199 100644
--- a/zbar/qrcode/qrdec.h
+++ b/zbar/qrcode/qrdec.h
@@ -140,6 +140,10 @@ struct qr_code_data {
Points appear in the order up-left, up-right, down-left, down-right,
relative to the orientation of the QR code.*/
qr_point bbox[4];
+
+ decodeErrorsInfo uec;
+ codeStructureInfo str;
+
};
struct qr_code_data_list {
diff --git a/zbar/qrcode/qrdectxt.c b/zbar/qrcode/qrdectxt.c
index 71c59cb..b53a98c 100644
--- a/zbar/qrcode/qrdectxt.c
+++ b/zbar/qrcode/qrdectxt.c
@@ -500,9 +500,20 @@ int qr_code_data_list_extract_text(const qr_code_data_list *_qrlist,
(char *)realloc(sa_text, sa_ntext * sizeof(*sa_text));
}
- if (sa_size == 1)
+ if (sa_size == 1) {
sa_sym = syms;
- else {
+ if (!qrdata[i].uec.readError) {
+ sa_sym->uec = qrdata[i].uec;
+ }
+ if (qrdata[i].str.valid) {
+ sa_sym->str.valid = qrdata[i].str.valid;
+ sa_sym->str.codeSize = qrdata[i].str.codeSize;
+ sa_sym->str.numBlocks = qrdata[i].str.numBlocks;
+ memcpy(sa_sym->str.numElems, qrdata[i].str.numElems, sizeof(*qrdata[i].str.numElems) * qrdata[i].str.numBlocks);
+ memcpy(sa_sym->str.blocks, qrdata[i].str.blocks, sizeof(*qrdata[i].str.blocks) * qrdata[i].str.numBlocks);
+ }
+
+ } else {
/* cheap out w/axis aligned bbox for now */
int xmin = img->width, xmax = -2;
int ymin = img->height, ymax = -2;
diff --git a/zbar/symbol.c b/zbar/symbol.c
index fe2a4f8..20a9866 100644
--- a/zbar/symbol.c
+++ b/zbar/symbol.c
@@ -223,6 +223,10 @@ void _zbar_symbol_free(zbar_symbol_t *sym)
free(sym->pts);
if (sym->data_alloc && sym->data)
free(sym->data);
+
+ if (sym->str.numElems) {free(sym->str.numElems); sym->str.numElems = NULL;}
+ if (sym->str.blocks) {free(sym->str.blocks); sym->str.blocks = NULL;}
+
free(sym);
}
@@ -511,3 +515,40 @@ zbar_symbol_set_first_unfiltered(const zbar_symbol_set_t *syms)
{
return (syms->head);
}
+
+float
+zbar_uec(const zbar_symbol_t* sym)
+{
+ if (sym->type != ZBAR_QRCODE) {
+ return -1;
+ }
+ if (!sym->uec.readError && sym->uec.checkedBlocks == sym->uec.totalBlocks) {
+ float minUEC = 1.0;
+ for (int i = 0; i < sym->uec.checkedBlocks; ++i) {
+ float blockUEC;
+ if (sym->uec.errors[i] > sym->uec.maxCorrectableErrors[i]) {
+ minUEC = 0.0;
+ break;
+ }
+ blockUEC = 1.0 - (float)sym->uec.errors[i] / sym->uec.maxCorrectableErrors[i];
+ if (blockUEC < minUEC) minUEC = blockUEC;
+ }
+ return minUEC;
+ }
+ else {
+ return 0.0;
+ }
+}
+codeStructureInfo*
+zbar_structure(const zbar_symbol_t* sym)
+{
+ return &sym->str;
+}
+int
+zbar_size(const zbar_symbol_t* sym)
+{
+ if (sym->type != ZBAR_QRCODE || !sym->str.valid) {
+ return -1;
+ }
+ return sym->str.codeSize;
+}
diff --git a/zbar/symbol.h b/zbar/symbol.h
index 5ea97a3..cfc78c4 100644
--- a/zbar/symbol.h
+++ b/zbar/symbol.h
@@ -59,6 +59,10 @@ struct zbar_symbol_s {
unsigned long time; /* relative symbol capture time */
int cache_count; /* cache state */
int quality; /* relative symbol reliability metric */
+
+ decodeErrorsInfo uec;
+ codeStructureInfo str;
+
};
extern int _zbar_get_symbol_hash(zbar_symbol_type_t);