Evaluate QR codes in accordance with ISO 18004 6.8

This commit is contained in:
Benjamin Kunz 2013-11-15 16:03:00 +01:00
parent d27db1f6e0
commit 2e5fe31ebf

View File

@ -39,6 +39,7 @@
#include "sjis.h" #include "sjis.h"
#include "qr.h" #include "qr.h"
#include "reedsol.h" #include "reedsol.h"
#include <stdlib.h> /* abs */
int in_alpha(int glyph) { int in_alpha(int glyph) {
/* Returns true if input glyph is in the Alphanumeric set */ /* Returns true if input glyph is in the Alphanumeric set */
@ -737,21 +738,54 @@ void populate_grid(unsigned char* grid, int size, int* datastream, int cw)
} while (i < n); } while (i < n);
} }
#ifdef ZINTLOG
int append_log(char log)
{
FILE *file;
file = fopen("zintlog.txt", "a+");
fprintf(file, "%c", log);
fclose(file);
return 0;
}
int write_log(char log[])
{
FILE *file;
file = fopen("zintlog.txt", "a+");
fprintf(file, log); /*writes*/
fprintf(file, "\r\n"); /*writes*/
fclose(file);
return 0;
}
#endif
int evaluate(unsigned char *grid, int size, int pattern) int evaluate(unsigned char *grid, int size, int pattern)
{ {
int x, y, block; int x, y, block;
int result = 0; int result = 0;
int result_b = 0;
char state; char state;
int p; int p;
int dark_mods; int dark_mods;
int percentage, k; int percentage, k, k2;
char str[15];
#ifndef _MSC_VER #ifndef _MSC_VER
char local[size * size]; char local[size * size];
#else #else
char* local = (char *)_alloca((size * size) * sizeof(char)); char* local = (char *)_alloca((size * size) * sizeof(char));
#endif #endif
#ifdef ZINTLOG
write_log("");
sprintf(str, "%d", pattern);
write_log(str);
#endif
// all eight bitmask variants have been encoded in the 8 bits of the bytes that make up the grid array. select them for evaluation according to the desired pattern.
for(x = 0; x < size; x++) { for(x = 0; x < size; x++) {
for(y = 0; y < size; y++) { for(y = 0; y < size; y++) {
switch(pattern) { switch(pattern) {
@ -767,25 +801,36 @@ int evaluate(unsigned char *grid, int size, int pattern)
} }
} }
#ifdef ZINTLOG
//bitmask output
for(y = 0; y < size; y++) {
strcpy (str, "");
for(x = 0; x < size; x++) {
state =local[(y * size) + x];
append_log(state);
}
write_log("");
}
write_log("");
#endif
/* Test 1: Adjacent modules in row/column in same colour */ /* Test 1: Adjacent modules in row/column in same colour */
/* Vertical */ /* Vertical */
for(x = 0; x < size; x++) { for(x = 0; x < size; x++) {
state = local[x]; state = local[x];
block = 0; block = 0;
for(y = 0; y < size; y++) { for(y = 0; y < size; y++) {
if(local[(y * size) + x] == state) { if(local[(y * size) + x] == state) {
block++; block++;
if(block ==5)
result += 3;
if(block>5)
result +=1;
} else { } else {
if(block > 5) { block=0;
result += (3 + block);
}
block = 0;
state = local[(y * size) + x];
} }
} }
if(block > 5) {
result += (3 + block);
}
} }
/* Horizontal */ /* Horizontal */
@ -794,35 +839,68 @@ int evaluate(unsigned char *grid, int size, int pattern)
block = 0; block = 0;
for(x = 0; x < size; x++) { for(x = 0; x < size; x++) {
if(local[(y * size) + x] == state) { if(local[(y * size) + x] == state) {
block++; block++;
if(block ==5)
result += 3;
if(block>5)
result +=1;
} else { } else {
if(block > 5) { block=0;
result += (3 + block);
}
block = 0;
state = local[(y * size) + x];
} }
} }
if(block > 5) { }
result += (3 + block);
#ifdef ZINTLOG
/* output Test 1 */
sprintf(str, "%d", result);
result_b=result;
write_log(str);
#endif
/* Test 2 fd02131114 */
for(x = 0; x < size-1; x++) {
for(y = 0; y < (size - 7) -1; y++) {
// y + 1???
if((local[((y + 1) * size) + x] == '1') &&
(local[((y + 1) * size) + x+1] == '1') &&
(local[(((y + 1)+1) * size) + x] == '1') &&
(local[(((y + 1)+1) * size) + x+1] == '1')
) { result += 3; }
if((local[((y + 1) * size) + x] == '0') &&
(local[((y + 1) * size) + x+1] == '0') &&
(local[(((y + 1)+1) * size) + x] == '0') &&
(local[(((y + 1)+1) * size) + x+1] == '0')
) { result += 3; }
} }
} }
/* Test 2 is not implimented */ #ifdef ZINTLOG
/* output Test 2 */
sprintf(str, "%d", result-result_b);
result_b=result;
write_log(str);
#endif
/* Test 3: 1:1:3:1:1 ratio pattern in row/column */ /* Test 3: fd02131114 */
/* Vertical */ /*pattern 10111010000 */
/* Vertical */
for(x = 0; x < size; x++) { for(x = 0; x < size; x++) {
for(y = 0; y < (size - 7); y++) { for(y = 0; y < (size - 11); y++) {
p = 0; p = 0;
if(local[(y * size) + x] == '1') { p += 0x40; } if(local[(y * size) + x] == '1') { p += 1; }
if(local[((y + 1) * size) + x] == '1') { p += 0x20; } if(local[((y + 1) * size) + x] == '0') { p += 1; }
if(local[((y + 2) * size) + x] == '1') { p += 0x10; } if(local[((y + 2) * size) + x] == '1') { p += 1; }
if(local[((y + 3) * size) + x] == '1') { p += 0x08; } if(local[((y + 3) * size) + x] == '1') { p += 1; }
if(local[((y + 4) * size) + x] == '1') { p += 0x04; } if(local[((y + 4) * size) + x] == '1') { p += 1; }
if(local[((y + 5) * size) + x] == '1') { p += 0x02; } if(local[((y + 5) * size) + x] == '0') { p += 1; }
if(local[((y + 6) * size) + x] == '1') { p += 0x01; } if(local[((y + 6) * size) + x] == '1') { p += 1; }
if(p == 0x5d) { if(local[((y + 7) * size) + x] == '0') { p += 1; }
if(local[((y + 8) * size) + x] == '0') { p += 1; }
if(local[((y + 9) * size) + x] == '0') { p += 1; }
if(local[((y + 10) * size) + x] == '0') { p += 1; }
if(p == 11) {
result += 40; result += 40;
} }
} }
@ -830,44 +908,151 @@ int evaluate(unsigned char *grid, int size, int pattern)
/* Horizontal */ /* Horizontal */
for(y = 0; y < size; y++) { for(y = 0; y < size; y++) {
for(x = 0; x < (size - 7); x++) { for(x = 0; x < (size - 11); x++) {
p = 0; p = 0;
if(local[(y * size) + x] == '1') { p += 0x40; } if(local[(y * size) + x] == '1') { p += 1; }
if(local[(y * size) + x + 1] == '1') { p += 0x20; } if(local[(y * size) + x + 1] == '0') { p += 1; }
if(local[(y * size) + x + 2] == '1') { p += 0x10; } if(local[(y * size) + x + 2] == '1') { p += 1; }
if(local[(y * size) + x + 3] == '1') { p += 0x08; } if(local[(y * size) + x + 3] == '1') { p += 1; }
if(local[(y * size) + x + 4] == '1') { p += 0x04; } if(local[(y * size) + x + 4] == '1') { p += 1; }
if(local[(y * size) + x + 5] == '1') { p += 0x02; } if(local[(y * size) + x + 5] == '0') { p += 1; }
if(local[(y * size) + x + 6] == '1') { p += 0x01; } if(local[(y * size) + x + 6] == '1') { p += 1; }
if(p == 0x5d) { if(local[(y * size) + x + 7] == '0') { p += 1; }
if(local[(y * size) + x + 8] == '0') { p += 1; }
if(local[(y * size) + x + 9] == '0') { p += 1; }
if(local[(y * size) + x + 10] == '0') { p += 1; }
if(p == 11) {
result += 40; result += 40;
} }
} }
} }
/*pattern 00001011101 */
/* Vertical */
for(x = 0; x < size; x++) {
for(y = 0; y < (size - 11); y++) {
p = 0;
if(local[(y * size) + x] == '0') { p += 1; }
if(local[((y + 1) * size) + x] == '0') { p += 1; }
if(local[((y + 2) * size) + x] == '0') { p += 1; }
if(local[((y + 3) * size) + x] == '0') { p += 1; }
if(local[((y + 4) * size) + x] == '1') { p += 1; }
if(local[((y + 5) * size) + x] == '0') { p += 1; }
if(local[((y + 6) * size) + x] == '1') { p += 1; }
if(local[((y + 7) * size) + x] == '1') { p += 1; }
if(local[((y + 8) * size) + x] == '1') { p += 1; }
if(local[((y + 9) * size) + x] == '0') { p += 1; }
if(local[((y + 10) * size) + x] == '1') { p += 1; }
if(p == 11) {
result += 40;
}
}
}
/* Horizontal */
for(y = 0; y < size; y++) {
for(x = 0; x < (size - 11); x++) {
p = 0;
if(local[(y * size) + x] == '0') { p += 1; }
if(local[(y * size) + x + 1] == '0') { p += 1; }
if(local[(y * size) + x + 2] == '0') { p += 1; }
if(local[(y * size) + x + 3] == '0') { p += 1; }
if(local[(y * size) + x + 4] == '1') { p += 1; }
if(local[(y * size) + x + 5] == '0') { p += 1; }
if(local[(y * size) + x + 6] == '1') { p += 1; }
if(local[(y * size) + x + 7] == '1') { p += 1; }
if(local[(y * size) + x + 8] == '1') { p += 1; }
if(local[(y * size) + x + 9] == '0') { p += 1; }
if(local[(y * size) + x + 10] == '1') { p += 1; }
if(p == 11) {
result += 40;
}
}
}
#ifdef ZINTLOG
/* output Test 3 */
sprintf(str, "%d", result-result_b);
result_b=result;
write_log(str);
#endif
/* Test 4: Proportion of dark modules in entire symbol */ /* Test 4: Proportion of dark modules in entire symbol */
dark_mods = 0; dark_mods = 0;
for(x = 0; x < size; x++) { for(x = 0; x < size; x++) {
for(y = 0; y < size; y++) { for(y = 0; y < size; y++) {
if(local[(y * size) + x] == '1') { if(local[(y * size) + x] == '1') {
dark_mods++; dark_mods++;
} }
} }
} }
percentage = 100 * (dark_mods / (size * size)); percentage = 100 * (dark_mods / (size * size));
if(percentage <= 50) { int m=0;
k = ((100 - percentage) - 50) / 5; for(x = 0; x < 100; x+=5) {
} else { if(x<percentage)
k = (percentage - 50) / 5; m=x;
} }
result += 10 * k;
k=abs((m-50)/5);
k2=abs((m+5-50)/5);
int smallest=k;
if(k2<smallest)
smallest=k2;
result += 10 * smallest;
#ifdef ZINTLOG
/* output Test 4+summary */
sprintf(str, "%d", result-result_b);
write_log(str);
write_log("==========");
sprintf(str, "%d", result);
write_log(str);
#endif
return result; return result;
} }
void add_format_info_eval(unsigned char *eval, int size, int ecc_level, int pattern)
{
/* Add format information to grid */
int apply_bitmask(unsigned char *grid, int size) int format = pattern;
unsigned int seq;
int i;
switch(ecc_level) {
case LEVEL_L: format += 0x08; break;
case LEVEL_Q: format += 0x18; break;
case LEVEL_H: format += 0x10; break;
}
seq = qr_annex_c[format];
for(i = 0; i < 6; i++) {
eval[(i * size) + 8] = (seq >> i) & 0x01 ? (0x01 >> pattern) : 0x00;
}
for(i = 0; i < 8; i++) {
eval[(8 * size) + (size - i - 1)] = (seq >> i) & 0x01 ? (0x01 >> pattern) : 0x00;
}
for(i = 0; i < 6; i++) {
eval[(8 * size) + (5 - i)] = (seq >> (i + 9)) & 0x01 ? (0x01 >> pattern) : 0x00;
}
for(i = 0; i < 7; i++) {
eval[(((size - 7) + i) * size) + 8] = (seq >> (i + 8)) & 0x01 ? (0x01 >> pattern) : 0x00;
}
eval[(7 * size) + 8] = (seq >> 6) & 0x01 ? (0x01 >> pattern) : 0x00;
eval[(8 * size) + 8] = (seq >> 7) & 0x01 ? (0x01 >> pattern) : 0x00;
eval[(8 * size) + 7] = (seq >> 8) & 0x01 ? (0x01 >> pattern) : 0x00;
}
int apply_bitmask(unsigned char *grid, int size, int ecc_level)
{ {
int x, y; int x, y;
unsigned char p; unsigned char p;
@ -887,8 +1072,9 @@ int apply_bitmask(unsigned char *grid, int size)
for(x = 0; x < size; x++) { for(x = 0; x < size; x++) {
for(y = 0; y < size; y++) { for(y = 0; y < size; y++) {
mask[(y * size) + x] = 0x00; mask[(y * size) + x] = 0x00;
if (!(grid[(y * size) + x] & 0xf0)) { // all eight bitmask variants are encoded in the 8 bits of the bytes that make up the mask array.
if (!(grid[(y * size) + x] & 0xf0)) { // exclude areas not to be masked.
if(((y + x) & 1) == 0) { mask[(y * size) + x] += 0x01; } if(((y + x) & 1) == 0) { mask[(y * size) + x] += 0x01; }
if((y & 1) == 0) { mask[(y * size) + x] += 0x02; } if((y & 1) == 0) { mask[(y * size) + x] += 0x02; }
if((x % 3) == 0) { mask[(y * size) + x] += 0x04; } if((x % 3) == 0) { mask[(y * size) + x] += 0x04; }
@ -901,9 +1087,12 @@ int apply_bitmask(unsigned char *grid, int size)
} }
} }
// apply data masks to grid, result in eval
for(x = 0; x < size; x++) { for(x = 0; x < size; x++) {
for(y = 0; y < size; y++) { for(y = 0; y < size; y++) {
if(grid[(y * size) + x] & 0x01) { p = 0xff; } else { p = 0x00; } if(grid[(y * size) + x] & 0x01)
{ p = 0xff; }
else { p = 0x00; }
eval[(y * size) + x] = mask[(y * size) + x] ^ p; eval[(y * size) + x] = mask[(y * size) + x] ^ p;
} }
@ -912,6 +1101,9 @@ int apply_bitmask(unsigned char *grid, int size)
/* Evaluate result */ /* Evaluate result */
for(pattern = 0; pattern < 8; pattern++) { for(pattern = 0; pattern < 8; pattern++) {
add_format_info_eval(eval, size, ecc_level, pattern);
penalty[pattern] = evaluate(eval, size, pattern); penalty[pattern] = evaluate(eval, size, pattern);
} }
@ -924,6 +1116,13 @@ int apply_bitmask(unsigned char *grid, int size)
} }
} }
#ifdef ZINTLOG
char str[15];
sprintf(str, "%d", best_val);
write_log("choosed pattern:");
write_log(str);
#endif
/* Apply mask */ /* Apply mask */
for(x = 0; x < size; x++) { for(x = 0; x < size; x++) {
for(y = 0; y < size; y++) { for(y = 0; y < size; y++) {
@ -995,12 +1194,12 @@ void add_version_info(unsigned char *grid, int size, int version)
long int version_data = qr_annex_d[version - 7]; long int version_data = qr_annex_d[version - 7];
for(i = 0; i < 6; i++) { for(i = 0; i < 6; i++) {
grid[((size - 11) * size) + i] += (version_data >> (i * 3)) & 0x01; grid[((size - 11) * size) + i] += (version_data >> (i * 3)) & 0x41;
grid[((size - 10) * size) + i] += (version_data >> ((i * 3) + 1)) & 0x01; grid[((size - 10) * size) + i] += (version_data >> ((i * 3) + 1)) & 0x41;
grid[((size - 9) * size) + i] += (version_data >> ((i * 3) + 2)) & 0x01; grid[((size - 9) * size) + i] += (version_data >> ((i * 3) + 2)) & 0x41;
grid[(i * size) + (size - 11)] += (version_data >> (i * 3)) & 0x01; grid[(i * size) + (size - 11)] += (version_data >> (i * 3)) & 0x41;
grid[(i * size) + (size - 10)] += (version_data >> ((i * 3) + 1)) & 0x01; grid[(i * size) + (size - 10)] += (version_data >> ((i * 3) + 1)) & 0x41;
grid[(i * size) + (size - 9)] += (version_data >> ((i * 3) + 2)) & 0x01; grid[(i * size) + (size - 9)] += (version_data >> ((i * 3) + 2)) & 0x41;
} }
} }
@ -1148,11 +1347,16 @@ int qr_code(struct zint_symbol *symbol, unsigned char source[], int length)
setup_grid(grid, size, version); setup_grid(grid, size, version);
populate_grid(grid, size, fullstream, qr_total_codewords[version - 1]); populate_grid(grid, size, fullstream, qr_total_codewords[version - 1]);
bitmask = apply_bitmask(grid, size);
add_format_info(grid, size, ecc_level, bitmask);
if(version >= 7) { if(version >= 7) {
add_version_info(grid, size, version); add_version_info(grid, size, version);
} }
bitmask = apply_bitmask(grid, size, ecc_level);
add_format_info(grid, size, ecc_level, bitmask);
symbol->width = size; symbol->width = size;
symbol->rows = size; symbol->rows = size;