a QR code generator for the command line
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

186 lines
4.7 KiB

#include <memory>
#include <getopt.h>
#include <iostream>
#include <sstream>
#include <qrcodegen.hpp>
#include "util.hpp"
#include "QR.hpp"
// Version is injected through cmake
constexpr const char* VERSION = "@qr_VERSION@";
void printHelp() {
std::string helpText = R"EOF(
qr is a tool for generating QR codes from the commandline
Usage: qr [OPTION]... --input "data to encapsulate"
*Caveats*
With no `--input` parameter defined, read STDIN
In pixel based renderers (i.e. PNG), the output code may not be exactly
centered, as the amount of segment may not correspond to the specified
output size.
Options:
-f --format output file format. can be one of "cli, png, svg, jpg, bmp"
-h --help show this help
-i --input take data from this argument instead of stdin
-o --output output file name without extension
-s --size desired output file size in pixels
-t --type output QR code type. can be one of "small, medium, large"
-v --version shows version info
Examples:
qr -i "this is from parameter" -f png -s 512 -o my_qrcode_file
echo "this is from stdin" | qr -t small -f png -s 512 -o my_qrcode_file_with_low_ecc
Copyright:
(C) 2023, MikO <miko@massivedynamic.eu>
*License*
Released under MIT license
Report bugs and issues at out issue tracker:
https://git.mike-ochmann.de/MassiveDynamic/qr/issues
)EOF";
std::cout << "qr " << VERSION;
std::cout << helpText << std::endl;
}
int main(int argc, char* argv[]) {
if (argc < 1) {
printHelp();
exit(1);
}
const option options[] = {
{"help", no_argument, nullptr, 'h'},
{"input", required_argument, nullptr, 'i'},
{"output", required_argument, nullptr, 'o'},
{"size", required_argument, nullptr, 's'},
{"type", required_argument, nullptr, 't'},
{"format", required_argument, nullptr, 'f'},
{"version", no_argument, nullptr, 'v'},
{nullptr}
};
std::string outputFile;
std::string paramData;
size_t segmentSize = 0;
bool fromStdin = true;
bool anyParameterSet = false;
qrcodegen::QrCode::Ecc type = qrcodegen::QrCode::Ecc::LOW;
massivedynamic::Format format = massivedynamic::Format::CONSOLE;
for(;;) {
int index = -1;
int result = getopt_long(argc, argv, "vho:s:t:f:i:", options, &index);
if (result == -1)
break;
anyParameterSet = true;
const option* opt = &options[index];
UNUSED(opt);
switch(result) {
case 'o': {
if (strlen(optarg) > 0)
outputFile = optarg;
break;
}
case 's': {
segmentSize = std::atoi(optarg);
break;
}
case 't': {
std::string value = optarg;
if (value == "small")
type = qrcodegen::QrCode::Ecc::LOW;
else if (value == "medium")
type = qrcodegen::QrCode::Ecc::MEDIUM;
else if (value == "large")
type = qrcodegen::QrCode::Ecc::HIGH;
else {
std::cerr << "ERROR: type (-t, --type) has to be one of 'small', 'medium' or 'large'" << std::endl;
printHelp();
return 1;
}
break;
}
case 'f': {
std::string value = optarg;
static_assert(massivedynamic::FormatLength == 5, "exhaustive formats: did you miss to add something here?");
if (value == "cli")
format = massivedynamic::Format::CONSOLE;
else if (value == "svg")
format = massivedynamic::Format::SVG;
else if (value == "png")
format = massivedynamic::Format::PNG;
else if (value == "jpg")
format = massivedynamic::Format::JPG;
else if (value == "bmp")
format = massivedynamic::Format::BMP;
else {
printHelp();
return 1;
}
break;
}
case 'i': {
fromStdin = false;
paramData = optarg;
break;
}
case 'v': {
std::cout << "qr " << VERSION << std::endl;
exit(0);
}
case 'h':
default:
printHelp();
return 0;
}
}
std::string line;
std::stringstream data;
if (fromStdin) {
if (!isatty(fileno(stdin))) {
while (std::getline(std::cin, line)) {
if (std::cin.eof() || line.empty()) {
std::cin.clear();
break;
}
data << line;
}
}
if (isatty(fileno(stdin)) || data.str().empty()) {
std::cerr << "ERROR: no data from stdinput." << std::endl;
if(!anyParameterSet)
printHelp();
exit(1);
}
} else
data << paramData;
if (data.str().empty()) {
std::cerr << "ERROR: input data is empty" << std::endl;
exit(1);
}
if ((format == massivedynamic::Format::PNG || format == massivedynamic::Format::SVG) && outputFile.empty()) {
std::cerr << "ERROR: output file name (-o, --output) can not be empty" << std::endl;
return 1;
}
std::unique_ptr<massivedynamic::QR> qr = std::make_unique<massivedynamic::QR>(data.str(), outputFile, segmentSize, type);
qr->render(format);
return 0;
}