Image-PNG-QRCode
view release on metacpan or search on metacpan
/*
This is a forked version of the qrduino project. The original is at
"https://github.com/tz1/qrduino". The author of this code is Tom
Zerucha, https://github.com/tz1.
This file is licenced under the GNU General Public Licence, version 3.
This file, "qrencode.c", contains all of the C code of the qrduino
project in one file, except for the jpeg code which I don't need
since I output to PNG.
This comment was added by Ben Bullock <benkasminbullock@gmail.com>,
on 2015-09-05.
*/
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include "qrencode.h"
#ifdef HEADER
typedef struct qr
{
char * input;
int input_length;
unsigned level;
unsigned version;
unsigned char * strinbuf;
unsigned char * qrframe;
/* The output modules. */
unsigned char *framebase;
/* The mask which covers the timing pattern, corners, etc. */
unsigned char *framask;
unsigned char *rlens;
/* Width of QR code. */
unsigned char WD;
unsigned char WDB;
unsigned char neccblk1;
unsigned char neccblk2;
unsigned char datablkw;
unsigned char eccblkwid;
unsigned initialized : 1;
}
qr_t;
#define QRBIT(f,x,y) ((qr->f[((x)>>3) + (y) * qr->WDB] >> (7-((x) & 7 ))) & 1 )
#define QR_MINIMUM_VERSION 1
#define QR_MAXIMUM_VERSION 40
#define QR_MINIMUM_LEVEL 1
#define QR_MAXIMUM_LEVEL 4
#endif /* def HEADER */
#define SETQRBIT(f,x,y) qr->f[((x)>>3) + (y) * qr->WDB] |= 0x80 >> ((x) & 7)
#define TOGQRBIT(f,x,y) qr->f[((x)>>3) + (y) * qr->WDB] ^= 0x80 >> ((x) & 7)
static void setmask(qr_t * qr, unsigned char x, unsigned char y)
{
unsigned bt;
if (x > y) {
bt = x;
x = y;
y = bt;
}
// y*y = 1+3+5...
bt = y;
bt *= y;
bt += y;
bt >>= 1;
bt += x;
qr->framask[bt >> 3] |= 0x80 >> (bt & 7);
}
/* Put the three 7x7 finder patterns on the three corners. */
static void putfind(qr_t * qr)
{
unsigned char j, i, k, t;
for (t = 0; t < 3; t++) {
/* Y offset */
k = 0;
/* X offset */
i = 0;
if (t == 1)
k = (qr->WD - 7);
if (t == 2)
i = (qr->WD - 7);
SETQRBIT(framebase,i + 3, k + 3);
/* Outer black rectangle */
for (j = 0; j < 6; j++) {
SETQRBIT(framebase,i + j, k);
SETQRBIT(framebase,i, k + j + 1);
SETQRBIT(framebase,i + 6, k + j);
SETQRBIT(framebase,i + j + 1, k + 6);
}
for (j = 1; j < 5; j++) {
setmask(qr, i + j, k + 1);
setmask(qr, i + 1, k + j + 1);
setmask(qr, i + 5, k + j);
setmask(qr, i + j + 1, k + 5);
}
for (j = 2; j < 4; j++) {
SETQRBIT(framebase,i + j, k + 2);
SETQRBIT(framebase,i + 2, k + j + 1);
SETQRBIT(framebase,i + 4, k + j);
SETQRBIT(framebase,i + j + 1, k + 4);
}
}
}
/* put the alignment patterns */
static void putalign(qr_t * qr, int x, int y)
{
int j;
SETQRBIT(framebase,x, y);
for (j = -2; j < 2; j++) {
SETQRBIT(framebase,x + j, y - 2);
SETQRBIT(framebase,x - 2, y + j + 1);
SETQRBIT(framebase,x + 2, y + j);
SETQRBIT(framebase,x + j + 1, y + 2);
}
for (j = 0; j < 2; j++) {
setmask(qr, x - 1, y + j);
setmask(qr, x + 1, y - j);
setmask(qr, x - j, y - 1);
setmask(qr, x + j, y + 1);
}
}
static const unsigned char adelta[41] = {
0, 11, 15, 19, 23, 27, 31, // force 1 pat
16, 18, 20, 22, 24, 26, 28, 20, 22, 24, 24, 26, 28, 28, 22, 24, 24,
26, 26, 28, 28, 24, 24, 26, 26, 26, 28, 28, 24, 26, 26, 26, 28, 28,
};
static void doaligns(qr_t * qr)
{
unsigned char delta, x, y;
if (qr->version < 2)
return;
delta = adelta[qr->version];
y = qr->WD - 7;
for (;;) {
x = qr->WD - 7;
while (x > delta - 3U) {
putalign(qr, x, y);
if (x < delta)
break;
x -= delta;
}
if (y <= delta + 9U)
break;
y -= delta;
putalign(qr, 6, y);
putalign(qr, y, 6);
}
}
static const unsigned vpat[] = {
0xc94, 0x5bc, 0xa99, 0x4d3, 0xbf6, 0x762, 0x847, 0x60d,
0x928, 0xb78, 0x45d, 0xa17, 0x532, 0x9a6, 0x683, 0x8c9,
0x7ec, 0xec4, 0x1e1, 0xfab, 0x08e, 0xc1a, 0x33f, 0xd75,
0x250, 0x9d5, 0x6f0, 0x8ba, 0x79f, 0xb0b, 0x42e, 0xa64,
0x541, 0xc69
};
static void putvpat(qr_t * qr)
{
unsigned char vers = qr->version;
unsigned char x, y, bc;
unsigned verinfo;
if (vers < 7)
return;
verinfo = vpat[vers - 7];
bc = 17;
for (x = 0; x < 6; x++) {
for (y = 0; y < 3; y++, bc--) {
if (1 & (bc > 11 ? vers >> (bc - 12) : verinfo >> bc)) {
SETQRBIT(framebase,5 - x, 2 - y + qr->WD - 11);
SETQRBIT(framebase,2 - y + qr->WD - 11, 5 - x);
}
else {
setmask(qr, 5 - x, 2 - y + qr->WD - 11);
setmask(qr, 2 - y + qr->WD - 11, 5 - x);
}
}
}
}
void initframe(qr_t * qr)
{
unsigned x, y;
qr->framebase = calloc(qr->WDB * qr->WD, 1);
qr->framask = calloc(((qr->WD * (qr->WD + 1) / 2) + 7) / 8, 1);
qr->rlens = malloc(qr->WD + 1);
// finders
putfind(qr);
// alignment blocks
doaligns(qr);
// single black
SETQRBIT(framebase,8, qr->WD - 8);
// timing gap - masks only
for (y = 0; y < 7; y++) {
setmask(qr, 7, y);
setmask(qr, qr->WD - 8, y);
setmask(qr, 7, y + qr->WD - 7);
}
for (x = 0; x < 8; x++) {
setmask(qr, x, 7);
setmask(qr, x + qr->WD - 8, 7);
setmask(qr, x, qr->WD - 8);
}
// reserve mask-format area
for (x = 0; x < 9; x++)
setmask(qr,x, 8);
for (x = 0; x < 8; x++) {
setmask(qr,x + qr->WD - 8, 8);
setmask(qr,8, x);
}
for (y = 0; y < 7; y++)
setmask(qr,8, y + qr->WD - 7);
// timing
for (x = 0; x < qr->WD - 14; x++) {
if (x & 1) {
setmask(qr,8 + x, 6);
setmask(qr,6, 8 + x);
}
else {
SETQRBIT(framebase,8 + x, 6);
SETQRBIT(framebase,6, 8 + x);
}
}
// version block
putvpat(qr);
for (y = 0; y < qr->WD; y++) {
for (x = 0; x <= y; x++) {
if (QRBIT(framebase,x, y)) {
setmask(qr,x, y);
}
}
}
}
static void freeframe(qr_t * qr)
{
free( qr->framebase );
free( qr->framask );
free( qr->rlens );
free (qr->qrframe);
free (qr->strinbuf);
}
static const unsigned char eccblocks[] = {
1, 0, 19, 7, 1, 0, 16, 10, 1, 0, 13, 13, 1, 0, 9, 17,
1, 0, 34, 10, 1, 0, 28, 16, 1, 0, 22, 22, 1, 0, 16, 28,
1, 0, 55, 15, 1, 0, 44, 26, 2, 0, 17, 18, 2, 0, 13, 22,
1, 0, 80, 20, 2, 0, 32, 18, 2, 0, 24, 26, 4, 0, 9, 16,
1, 0,108, 26, 2, 0, 43, 24, 2, 2, 15, 18, 2, 2, 11, 22,
2, 0, 68, 18, 4, 0, 27, 16, 4, 0, 19, 24, 4, 0, 15, 28,
2, 0, 78, 20, 4, 0, 31, 18, 2, 4, 14, 18, 4, 1, 13, 26,
2, 0, 97, 24, 2, 2, 38, 22, 4, 2, 18, 22, 4, 2, 14, 26,
2, 0,116, 30, 3, 2, 36, 22, 4, 4, 16, 20, 4, 4, 12, 24,
2, 2, 68, 18, 4, 1, 43, 26, 6, 2, 19, 24, 6, 2, 15, 28,
4, 0, 81, 20, 1, 4, 50, 30, 4, 4, 22, 28, 3, 8, 12, 24,
2, 2, 92, 24, 6, 2, 36, 22, 4, 6, 20, 26, 7, 4, 14, 28,
4, 0,107, 26, 8, 1, 37, 22, 8, 4, 20, 24, 12, 4, 11, 22,
3, 1,115, 30, 4, 5, 40, 24, 11, 5, 16, 20, 11, 5, 12, 24,
5, 1, 87, 22, 5, 5, 41, 24, 5, 7, 24, 30, 11, 7, 12, 24,
5, 1, 98, 24, 7, 3, 45, 28, 15, 2, 19, 24, 3,13, 15, 30,
1, 5,107, 28, 10, 1, 46, 28, 1,15, 22, 28, 2,17, 14, 28,
5, 1,120, 30, 9, 4, 43, 26, 17, 1, 22, 28, 2,19, 14, 28,
3, 4,113, 28, 3,11, 44, 26, 17, 4, 21, 26, 9,16, 13, 26,
3, 5,107, 28, 3,13, 41, 26, 15, 5, 24, 30, 15,10, 15, 28,
4, 4,116, 28, 17, 0, 42, 26, 17, 6, 22, 28, 19, 6, 16, 30,
2, 7,111, 28, 17, 0, 46, 28, 7,16, 24, 30, 34, 0, 13, 24,
4, 5,121, 30, 4,14, 47, 28, 11,14, 24, 30, 16,14, 15, 30,
6, 4,117, 30, 6,14, 45, 28, 11,16, 24, 30, 30, 2, 16, 30,
8, 4,106, 26, 8,13, 47, 28, 7,22, 24, 30, 22,13, 15, 30,
10, 2,114, 28, 19, 4, 46, 28, 28, 6, 22, 28, 33, 4, 16, 30,
8, 4,122, 30, 22, 3, 45, 28, 8,26, 23, 30, 12,28, 15, 30,
3,10,117, 30, 3,23, 45, 28, 4,31, 24, 30, 11,31, 15, 30,
7, 7,116, 30, 21, 7, 45, 28, 1,37, 23, 30, 19,26, 15, 30,
5,10,115, 30, 19,10, 47, 28, 15,25, 24, 30, 23,25, 15, 30,
13, 3,115, 30, 2,29, 46, 28, 42, 1, 24, 30, 23,28, 15, 30,
17, 0,115, 30, 10,23, 46, 28, 10,35, 24, 30, 19,35, 15, 30,
17, 1,115, 30, 14,21, 46, 28, 29,19, 24, 30, 11,46, 15, 30,
13, 6,115, 30, 14,23, 46, 28, 44, 7, 24, 30, 59, 1, 16, 30,
12, 7,121, 30, 12,26, 47, 28, 39,14, 24, 30, 22,41, 15, 30,
6,14,121, 30, 6,34, 47, 28, 46,10, 24, 30, 2,64, 15, 30,
17, 4,122, 30, 29,14, 46, 28, 49,10, 24, 30, 24,46, 15, 30,
4,18,122, 30, 13,32, 46, 28, 48,14, 24, 30, 42,32, 15, 30,
20, 4,117, 30, 40, 7, 47, 28, 43,22, 24, 30, 10,67, 15, 30,
19, 6,118, 30, 18,31, 47, 28, 34,34, 24, 30, 20,61, 15, 30,
};
unsigned initecc(qr_t * qr)
{
assert (qr->version >= QR_MINIMUM_VERSION &&
( run in 0.976 second using v1.01-cache-2.11-cpan-df04353d9ac )