Image-PNG-QRCode

 view release on metacpan or  search on metacpan

qrencode.c  view on Meta::CPAN

/*
  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 )