/* * qrencode - QR Code encoder * * Micor QR Code specification in convenient format. * Copyright (C) 2006-2011 Kentaro Fukuchi * * The following data / specifications are taken from * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) * or * "Automatic identification and data capture techniques -- * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #if HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #ifdef HAVE_LIBPTHREAD #include #endif #include "mqrspec.h" /****************************************************************************** * Version and capacity *****************************************************************************/ typedef struct { int width; //< Edge length of the symbol int ec[4]; //< Number of ECC code (bytes) } MQRspec_Capacity; /** * Table of the capacity of symbols * See Table 1 (pp.106) and Table 8 (pp.113) of Appendix 1, JIS X0510:2004. */ static const MQRspec_Capacity mqrspecCapacity[MQRSPEC_VERSION_MAX + 1] = { { 0, {0, 0, 0, 0}}, { 11, {2, 0, 0, 0}}, { 13, {5, 6, 0, 0}}, { 15, {6, 8, 0, 0}}, { 17, {8, 10, 14, 0}} }; int MQRspec_getDataLengthBit(int version, QRecLevel level) { int w; int ecc; w = mqrspecCapacity[version].width - 1; ecc = mqrspecCapacity[version].ec[level]; if(ecc == 0) return 0; return w * w - 64 - ecc * 8; } int MQRspec_getDataLength(int version, QRecLevel level) { return (MQRspec_getDataLengthBit(version, level) + 4) / 8; } int MQRspec_getECCLength(int version, QRecLevel level) { return mqrspecCapacity[version].ec[level]; } int MQRspec_getWidth(int version) { return mqrspecCapacity[version].width; } /****************************************************************************** * Length indicator *****************************************************************************/ /** * See Table 3 (pp.107) of Appendix 1, JIS X0510:2004. */ static const int lengthTableBits[4][4] = { { 3, 4, 5, 6}, { 0, 3, 4, 5}, { 0, 0, 4, 5}, { 0, 0, 3, 4} }; int MQRspec_lengthIndicator(QRencodeMode mode, int version) { return lengthTableBits[mode][version - 1]; } int MQRspec_maximumWords(QRencodeMode mode, int version) { int bits; int words; bits = lengthTableBits[mode][version - 1]; words = (1 << bits) - 1; if(mode == QR_MODE_KANJI) { words *= 2; // the number of bytes is required } return words; } /****************************************************************************** * Format information *****************************************************************************/ /* See calcFormatInfo in tests/test_mqrspec.c */ static const unsigned int formatInfo[4][8] = { {0x4445, 0x55ae, 0x6793, 0x7678, 0x06de, 0x1735, 0x2508, 0x34e3}, {0x4172, 0x5099, 0x62a4, 0x734f, 0x03e9, 0x1202, 0x203f, 0x31d4}, {0x4e2b, 0x5fc0, 0x6dfd, 0x7c16, 0x0cb0, 0x1d5b, 0x2f66, 0x3e8d}, {0x4b1c, 0x5af7, 0x68ca, 0x7921, 0x0987, 0x186c, 0x2a51, 0x3bba} }; /* See Table 10 of Appendix 1. (pp.115) */ static const int typeTable[MQRSPEC_VERSION_MAX + 1][3] = { {-1, -1, -1}, { 0, -1, -1}, { 1, 2, -1}, { 3, 4, -1}, { 5, 6, 7} }; unsigned int MQRspec_getFormatInfo(int mask, int version, QRecLevel level) { int type; if(mask < 0 || mask > 3) return 0; if(version <= 0 || version > MQRSPEC_VERSION_MAX) return 0; if(level == QR_ECLEVEL_H) return 0; type = typeTable[version][level]; if(type < 0) return 0; return formatInfo[mask][type]; } /****************************************************************************** * Frame *****************************************************************************/ /** * Cache of initial frames. */ /* C99 says that static storage shall be initialized to a null pointer * by compiler. */ static unsigned char *frames[MQRSPEC_VERSION_MAX + 1]; #ifdef HAVE_LIBPTHREAD static pthread_mutex_t frames_mutex = PTHREAD_MUTEX_INITIALIZER; #endif /** * Put a finder pattern. * @param frame * @param width * @param ox,oy upper-left coordinate of the pattern */ static void putFinderPattern(unsigned char *frame, int width, int ox, int oy) { static const unsigned char finder[] = { 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, }; int x, y; const unsigned char *s; frame += oy * width + ox; s = finder; for(y=0; y<7; y++) { for(x=0; x<7; x++) { frame[x] = s[x]; } frame += width; s += 7; } } static unsigned char *MQRspec_createFrame(int version) { unsigned char *frame, *p, *q; int width; int x, y; width = mqrspecCapacity[version].width; frame = (unsigned char *)malloc(width * width); if(frame == NULL) return NULL; memset(frame, 0, width * width); /* Finder pattern */ putFinderPattern(frame, width, 0, 0); /* Separator */ p = frame; for(y=0; y<7; y++) { p[7] = 0xc0; p += width; } memset(frame + width * 7, 0xc0, 8); /* Mask format information area */ memset(frame + width * 8 + 1, 0x84, 8); p = frame + width + 8; for(y=0; y<7; y++) { *p = 0x84; p += width; } /* Timing pattern */ p = frame + 8; q = frame + width * 8; for(x=1; x MQRSPEC_VERSION_MAX) return NULL; #ifdef HAVE_LIBPTHREAD pthread_mutex_lock(&frames_mutex); #endif if(frames[version] == NULL) { frames[version] = MQRspec_createFrame(version); } #ifdef HAVE_LIBPTHREAD pthread_mutex_unlock(&frames_mutex); #endif if(frames[version] == NULL) return NULL; width = mqrspecCapacity[version].width; frame = (unsigned char *)malloc(width * width); if(frame == NULL) return NULL; memcpy(frame, frames[version], width * width); return frame; } void MQRspec_clearCache(void) { int i; #ifdef HAVE_LIBPTHREAD pthread_mutex_lock(&frames_mutex); #endif for(i=1; i<=MQRSPEC_VERSION_MAX; i++) { free(frames[i]); frames[i] = NULL; } #ifdef HAVE_LIBPTHREAD pthread_mutex_unlock(&frames_mutex); #endif }