|
|
|
@ -1,4 +1,4 @@
|
|
|
|
|
/*
|
|
|
|
|
/*
|
|
|
|
|
* QR Code generator demo (C++)
|
|
|
|
|
*
|
|
|
|
|
* Run this command-line program with no arguments. The program computes a bunch of demonstration
|
|
|
|
@ -24,8 +24,9 @@
|
|
|
|
|
* Software.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define _CRT_SECURE_NO_DEPRECATE
|
|
|
|
|
|
|
|
|
|
#include <climits>
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
#include <cstring>
|
|
|
|
|
#include <iostream>
|
|
|
|
@ -33,12 +34,16 @@
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include "qrcodegen.hpp"
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
|
|
using std::uint8_t;
|
|
|
|
|
using qrcodegen::QrCode;
|
|
|
|
|
using qrcodegen::QrSegment;
|
|
|
|
|
|
|
|
|
|
#pragma pack(2)// need this, otherwise cant get correct result of sizeof
|
|
|
|
|
|
|
|
|
|
#pragma pack(2)//必须得写,否则sizeof得不到正确的结果
|
|
|
|
|
|
|
|
|
|
typedef unsigned char BYTE;
|
|
|
|
|
typedef unsigned short WORD;
|
|
|
|
@ -66,6 +71,84 @@ typedef struct {
|
|
|
|
|
DWORD biClrImportant;
|
|
|
|
|
} BITMAPINFOHEADER;
|
|
|
|
|
|
|
|
|
|
int SaveToBMP(const QrCode& qrCode) // to 145*145
|
|
|
|
|
{
|
|
|
|
|
//将要生成的二维码保存为BMP真彩色图片文件
|
|
|
|
|
FILE* pf = fopen("qrcode.bmp", "wb");
|
|
|
|
|
if (NULL == pf)
|
|
|
|
|
{
|
|
|
|
|
printf("file open fail.\n");
|
|
|
|
|
fclose(pf);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
int width = qrCode.getSize();
|
|
|
|
|
int height = qrCode.getSize();
|
|
|
|
|
int biCount = 24;//真彩色
|
|
|
|
|
int lineByte = (width * biCount / 8 + 3) / 4 * 4; //每line字节数必须为4的倍数
|
|
|
|
|
|
|
|
|
|
//位图文件头
|
|
|
|
|
BITMAPFILEHEADER bitMapFileHeader;
|
|
|
|
|
bitMapFileHeader.bfType = 0x4D42;
|
|
|
|
|
bitMapFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + lineByte * height;
|
|
|
|
|
bitMapFileHeader.bfReserved1 = 0;
|
|
|
|
|
bitMapFileHeader.bfReserved2 = 0;
|
|
|
|
|
bitMapFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
|
|
|
|
|
|
|
|
|
//位图信息头
|
|
|
|
|
BITMAPINFOHEADER bitMapInfoHeader;
|
|
|
|
|
bitMapInfoHeader.biBitCount = biCount;
|
|
|
|
|
bitMapInfoHeader.biClrImportant = 0;
|
|
|
|
|
bitMapInfoHeader.biClrUsed = 0;
|
|
|
|
|
bitMapInfoHeader.biCompression = 0;
|
|
|
|
|
bitMapInfoHeader.biHeight = height;
|
|
|
|
|
bitMapInfoHeader.biPlanes = 1;
|
|
|
|
|
bitMapInfoHeader.biSize = 40;
|
|
|
|
|
bitMapInfoHeader.biSizeImage = lineByte * height;
|
|
|
|
|
bitMapInfoHeader.biWidth = width;
|
|
|
|
|
bitMapInfoHeader.biXPelsPerMeter = 0;
|
|
|
|
|
bitMapInfoHeader.biYPelsPerMeter = 0;
|
|
|
|
|
//写文件头进文件
|
|
|
|
|
fwrite(&bitMapFileHeader, sizeof(BITMAPFILEHEADER), 1, pf);
|
|
|
|
|
//写位图信息头进文件
|
|
|
|
|
fwrite(&bitMapInfoHeader, sizeof(BITMAPINFOHEADER), 1, pf);
|
|
|
|
|
unsigned char* pBMPData = new unsigned char[lineByte * height];
|
|
|
|
|
memset(pBMPData, 255, lineByte * height);
|
|
|
|
|
|
|
|
|
|
for (int y = 0; y < height; y++)
|
|
|
|
|
{
|
|
|
|
|
for (int x = 0; x < height; x++)
|
|
|
|
|
{
|
|
|
|
|
//qrCode.getModule(x, y) ? printf("##") : printf(" ");
|
|
|
|
|
qrCode.getModule(x, y) ? printf("%c%c", 219, 219) : printf(" ");
|
|
|
|
|
}
|
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
}
|
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < height; i++)
|
|
|
|
|
{
|
|
|
|
|
for (int j = 0; j < lineByte / 3; j++)
|
|
|
|
|
{
|
|
|
|
|
if (qrCode.getModule(j, i))
|
|
|
|
|
{
|
|
|
|
|
//设置rgb颜色,可自定义设置,这里设为黑色。
|
|
|
|
|
*(pBMPData + lineByte * i + 3 * j) = 0;
|
|
|
|
|
*(pBMPData + lineByte * i + 3 * j + 1) = 0;
|
|
|
|
|
*(pBMPData + lineByte * i + 3 * j + 2) = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//写数据进文件
|
|
|
|
|
fwrite(pBMPData, sizeof(unsigned char), lineByte * height, pf);
|
|
|
|
|
fclose(pf);
|
|
|
|
|
delete[] pBMPData;
|
|
|
|
|
pBMPData = NULL;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Function prototypes
|
|
|
|
|
static void doBasicDemo();
|
|
|
|
@ -79,41 +162,40 @@ static void printQr(const QrCode &qr);
|
|
|
|
|
// The main application program.
|
|
|
|
|
int main() {
|
|
|
|
|
doBasicDemo();
|
|
|
|
|
doVarietyDemo();
|
|
|
|
|
doSegmentDemo();
|
|
|
|
|
doMaskDemo();
|
|
|
|
|
//doVarietyDemo();
|
|
|
|
|
//doSegmentDemo();
|
|
|
|
|
//doMaskDemo();
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*---- Demo suite ----*/
|
|
|
|
|
|
|
|
|
|
// Creates a single QR Code, then prints it to the console.
|
|
|
|
|
static void doBasicDemo() {
|
|
|
|
|
const char *text = "Hello, world!"; // User-supplied text
|
|
|
|
|
const QrCode::Ecc errCorLvl = QrCode::Ecc::LOW; // Error correction level
|
|
|
|
|
const char *text = "https://www.baidu.com/"; // User-supplied text
|
|
|
|
|
const QrCode::Ecc errCorLvl = QrCode::LOW; // Error correction level
|
|
|
|
|
|
|
|
|
|
// Make and print the QR Code symbol
|
|
|
|
|
const QrCode qr = QrCode::encodeText(text, errCorLvl);
|
|
|
|
|
printQr(qr);
|
|
|
|
|
std::cout << toSvgString(qr, 4) << std::endl;
|
|
|
|
|
//printQr(qr);
|
|
|
|
|
|
|
|
|
|
SaveToBMP(qr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Creates a variety of QR Codes that exercise different features of the library, and prints each one to the console.
|
|
|
|
|
static void doVarietyDemo() {
|
|
|
|
|
// Numeric mode encoding (3.33 bits per digit)
|
|
|
|
|
const QrCode qr0 = QrCode::encodeText("314159265358979323846264338327950288419716939937510", QrCode::Ecc::MEDIUM);
|
|
|
|
|
const QrCode qr0 = QrCode::encodeText("314159265358979323846264338327950288419716939937510", QrCode::MEDIUM);
|
|
|
|
|
printQr(qr0);
|
|
|
|
|
|
|
|
|
|
// Alphanumeric mode encoding (5.5 bits per character)
|
|
|
|
|
const QrCode qr1 = QrCode::encodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", QrCode::Ecc::HIGH);
|
|
|
|
|
const QrCode qr1 = QrCode::encodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", QrCode::HIGH);
|
|
|
|
|
printQr(qr1);
|
|
|
|
|
|
|
|
|
|
// Unicode text as UTF-8
|
|
|
|
|
const QrCode qr2 = QrCode::encodeText("\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1wa\xE3\x80\x81"
|
|
|
|
|
"\xE4\xB8\x96\xE7\x95\x8C\xEF\xBC\x81\x20\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4", QrCode::Ecc::QUARTILE);
|
|
|
|
|
"\xE4\xB8\x96\xE7\x95\x8C\xEF\xBC\x81\x20\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4", QrCode::QUARTILE);
|
|
|
|
|
printQr(qr2);
|
|
|
|
|
|
|
|
|
|
// Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland)
|
|
|
|
@ -124,7 +206,7 @@ static void doVarietyDemo() {
|
|
|
|
|
"'without pictures or conversations?' So she was considering in her own mind (as well as she could, "
|
|
|
|
|
"for the hot day made her feel very sleepy and stupid), whether the pleasure of making a "
|
|
|
|
|
"daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly "
|
|
|
|
|
"a White Rabbit with pink eyes ran close by her.", QrCode::Ecc::HIGH);
|
|
|
|
|
"a White Rabbit with pink eyes ran close by her.", QrCode::HIGH);
|
|
|
|
|
printQr(qr3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -136,12 +218,13 @@ static void doSegmentDemo() {
|
|
|
|
|
const char *silver1 = "41421356237309504880168872420969807856967187537694807317667973799";
|
|
|
|
|
const QrCode qr0 = QrCode::encodeText(
|
|
|
|
|
(std::string(silver0) + silver1).c_str(),
|
|
|
|
|
QrCode::Ecc::LOW);
|
|
|
|
|
QrCode::LOW);
|
|
|
|
|
printQr(qr0);
|
|
|
|
|
|
|
|
|
|
const QrCode qr1 = QrCode::encodeSegments(
|
|
|
|
|
{QrSegment::makeAlphanumeric(silver0), QrSegment::makeNumeric(silver1)},
|
|
|
|
|
QrCode::Ecc::LOW);
|
|
|
|
|
std::vector<QrSegment> segs;
|
|
|
|
|
segs.push_back(QrSegment::makeAlphanumeric(silver0));
|
|
|
|
|
segs.push_back(QrSegment::makeAlphanumeric(silver1));
|
|
|
|
|
const QrCode qr1 = QrCode::encodeSegments(segs, QrCode::LOW);
|
|
|
|
|
printQr(qr1);
|
|
|
|
|
|
|
|
|
|
// Illustration "golden"
|
|
|
|
@ -150,13 +233,15 @@ static void doSegmentDemo() {
|
|
|
|
|
const char *golden2 = "......";
|
|
|
|
|
const QrCode qr2 = QrCode::encodeText(
|
|
|
|
|
(std::string(golden0) + golden1 + golden2).c_str(),
|
|
|
|
|
QrCode::Ecc::LOW);
|
|
|
|
|
QrCode::LOW);
|
|
|
|
|
printQr(qr2);
|
|
|
|
|
|
|
|
|
|
std::vector<uint8_t> bytes(golden0, golden0 + std::strlen(golden0));
|
|
|
|
|
const QrCode qr3 = QrCode::encodeSegments(
|
|
|
|
|
{QrSegment::makeBytes(bytes), QrSegment::makeNumeric(golden1), QrSegment::makeAlphanumeric(golden2)},
|
|
|
|
|
QrCode::Ecc::LOW);
|
|
|
|
|
std::vector<QrSegment> segs3;
|
|
|
|
|
segs3.push_back(QrSegment::makeBytes(bytes));
|
|
|
|
|
segs3.push_back(QrSegment::makeNumeric(golden1));
|
|
|
|
|
segs3.push_back(QrSegment::makeAlphanumeric(golden2));
|
|
|
|
|
const QrCode qr3 = QrCode::encodeSegments(segs3, QrCode::LOW);
|
|
|
|
|
printQr(qr3);
|
|
|
|
|
|
|
|
|
|
// Illustration "Madoka": kanji, kana, Cyrillic, full-width Latin, Greek characters
|
|
|
|
@ -170,24 +255,24 @@ static void doSegmentDemo() {
|
|
|
|
|
"\xEF\xBD\x84\xEF\xBD\x85\xEF\xBD\x93\xEF"
|
|
|
|
|
"\xBD\x95\xE3\x80\x80\xCE\xBA\xCE\xB1\xEF"
|
|
|
|
|
"\xBC\x9F";
|
|
|
|
|
const QrCode qr4 = QrCode::encodeText(madoka, QrCode::Ecc::LOW);
|
|
|
|
|
const QrCode qr4 = QrCode::encodeText(madoka, QrCode::LOW);
|
|
|
|
|
printQr(qr4);
|
|
|
|
|
|
|
|
|
|
const std::vector<int> kanjiChars{ // Kanji mode encoding (13 bits per character)
|
|
|
|
|
0x0035, 0x1002, 0x0FC0, 0x0AED, 0x0AD7,
|
|
|
|
|
0x015C, 0x0147, 0x0129, 0x0059, 0x01BD,
|
|
|
|
|
0x018D, 0x018A, 0x0036, 0x0141, 0x0144,
|
|
|
|
|
0x0001, 0x0000, 0x0249, 0x0240, 0x0249,
|
|
|
|
|
0x0000, 0x0104, 0x0105, 0x0113, 0x0115,
|
|
|
|
|
0x0000, 0x0208, 0x01FF, 0x0008,
|
|
|
|
|
};
|
|
|
|
|
qrcodegen::BitBuffer bb;
|
|
|
|
|
for (int c : kanjiChars)
|
|
|
|
|
bb.appendBits(static_cast<std::uint32_t>(c), 13);
|
|
|
|
|
const QrCode qr5 = QrCode::encodeSegments(
|
|
|
|
|
{QrSegment(QrSegment::Mode::KANJI, static_cast<int>(kanjiChars.size()), bb)},
|
|
|
|
|
QrCode::Ecc::LOW);
|
|
|
|
|
printQr(qr5);
|
|
|
|
|
//const std::vector<int> kanjiChars{ // Kanji mode encoding (13 bits per character)
|
|
|
|
|
// 0x0035, 0x1002, 0x0FC0, 0x0AED, 0x0AD7,
|
|
|
|
|
// 0x015C, 0x0147, 0x0129, 0x0059, 0x01BD,
|
|
|
|
|
// 0x018D, 0x018A, 0x0036, 0x0141, 0x0144,
|
|
|
|
|
// 0x0001, 0x0000, 0x0249, 0x0240, 0x0249,
|
|
|
|
|
// 0x0000, 0x0104, 0x0105, 0x0113, 0x0115,
|
|
|
|
|
// 0x0000, 0x0208, 0x01FF, 0x0008,
|
|
|
|
|
//};
|
|
|
|
|
//qrcodegen::BitBuffer bb;
|
|
|
|
|
//for (int c : kanjiChars)
|
|
|
|
|
// bb.appendBits(static_cast<std::uint32_t>(c), 13);
|
|
|
|
|
//const QrCode qr5 = QrCode::encodeSegments(
|
|
|
|
|
// {QrSegment(QrSegment::Mode::KANJI, static_cast<int>(kanjiChars.size()), bb)},
|
|
|
|
|
// QrCode::LOW);
|
|
|
|
|
//printQr(qr5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -195,8 +280,8 @@ static void doSegmentDemo() {
|
|
|
|
|
static void doMaskDemo() {
|
|
|
|
|
// Project Nayuki URL
|
|
|
|
|
std::vector<QrSegment> segs0 = QrSegment::makeSegments("https://www.nayuki.io/");
|
|
|
|
|
printQr(QrCode::encodeSegments(segs0, QrCode::Ecc::HIGH, QrCode::MIN_VERSION, QrCode::MAX_VERSION, -1, true)); // Automatic mask
|
|
|
|
|
printQr(QrCode::encodeSegments(segs0, QrCode::Ecc::HIGH, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 3, true)); // Force mask 3
|
|
|
|
|
printQr(QrCode::encodeSegments(segs0, QrCode::HIGH, QrCode::MIN_VERSION, QrCode::MAX_VERSION, -1, true)); // Automatic mask
|
|
|
|
|
printQr(QrCode::encodeSegments(segs0, QrCode::HIGH, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 3, true)); // Force mask 3
|
|
|
|
|
|
|
|
|
|
// Chinese text as UTF-8
|
|
|
|
|
std::vector<QrSegment> segs1 = QrSegment::makeSegments(
|
|
|
|
@ -207,10 +292,10 @@ static void doMaskDemo() {
|
|
|
|
|
"\xE3\x80\x81\xE5\x85\xAC\xE9\x96\x8B\xE7\xB7\xA8\xE8\xBC\xAF\xE4\xB8\x94\xE5\xA4"
|
|
|
|
|
"\x9A\xE8\xAA\x9E\xE8\xA8\x80\xE7\x9A\x84\xE7\xB6\xB2\xE8\xB7\xAF\xE7\x99\xBE\xE7"
|
|
|
|
|
"\xA7\x91\xE5\x85\xA8\xE6\x9B\xB8\xE5\x8D\x94\xE4\xBD\x9C\xE8\xA8\x88\xE7\x95\xAB");
|
|
|
|
|
printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 0, true)); // Force mask 0
|
|
|
|
|
printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 1, true)); // Force mask 1
|
|
|
|
|
printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 5, true)); // Force mask 5
|
|
|
|
|
printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 7, true)); // Force mask 7
|
|
|
|
|
printQr(QrCode::encodeSegments(segs1, QrCode::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 0, true)); // Force mask 0
|
|
|
|
|
printQr(QrCode::encodeSegments(segs1, QrCode::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 1, true)); // Force mask 1
|
|
|
|
|
printQr(QrCode::encodeSegments(segs1, QrCode::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 5, true)); // Force mask 5
|
|
|
|
|
printQr(QrCode::encodeSegments(segs1, QrCode::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 7, true)); // Force mask 7
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -246,15 +331,18 @@ static std::string toSvgString(const QrCode &qr, int border) {
|
|
|
|
|
return sb.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Prints the given QrCode object to the console.
|
|
|
|
|
static void printQr(const QrCode &qr) {
|
|
|
|
|
int border = 4;
|
|
|
|
|
for (int y = -border; y < qr.getSize() + border; y++) {
|
|
|
|
|
for (int x = -border; x < qr.getSize() + border; x++) {
|
|
|
|
|
std::cout << (qr.getModule(x, y) ? "##" : " ");
|
|
|
|
|
qr.getModule(x, y) ? printf("%c%c", 219, 219) : printf(" ");
|
|
|
|
|
}
|
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
}
|
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|