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
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;
|
|
}
|
|
|