// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This helper binary can be compiled to aid in development / debugging of the
// QR generation code. It prints a QR code to the console and thus allows much
// faster iteration. It is not built by default, see the BUILD.gn in this
// directory.
#include <stdio.h>
#include <optional>
#include <utility>
#include "base/containers/span.h"
#include "base/strings/string_number_conversions.h"
#include "components/qr_code_generator/qr_code_generator.h"
// kTerminalBackgroundIsBright controls the output polarity. Many QR scanners
// will cope with inverted bright / dark but, if you have a bright terminal
// background, you may need to change this.
constexpr bool kTerminalBackgroundIsBright = false;
// kPaint is a pair of UTF-8 encoded code points for U+2588 ("FULL BLOCK").
static constexpr char kPaint[] = "\xe2\x96\x88\xe2\x96\x88";
static constexpr char kNoPaint[] = " ";
static void PrintHorizontalLine(const char* white, int size) {
for (int x = 0; x < size + 2; x++) {
fputs(white, stdout);
}
fputs("\n", stdout);
}
int main(int argc, char** argv) {
// Presubmits don't allow fprintf to a variable called |stderr|.
FILE* const STDERR = stderr;
if (argc < 2 || argc > 3) {
fprintf(STDERR, "Usage: %s <input string> [mask number]\n", argv[0]);
return 1;
}
const uint8_t* const input = reinterpret_cast<const uint8_t*>(argv[1]);
const size_t input_len = strlen(argv[1]);
std::optional<uint8_t> mask;
if (argc == 3) {
unsigned mask_unsigned;
if (!base::StringToUint(argv[2], &mask_unsigned) || mask_unsigned > 7) {
fprintf(STDERR, "Mask numbers run from zero to seven.\n");
return 1;
}
mask = static_cast<uint8_t>(mask_unsigned);
}
const char* black = kNoPaint;
const char* white = kPaint;
if (kTerminalBackgroundIsBright) {
std::swap(black, white);
}
auto code = qr_code_generator::GenerateCode(
base::span<const uint8_t>(input, input_len), mask);
if (!code.has_value()) {
fprintf(STDERR, "Input too long to be encoded.\n");
return 2;
}
const int size = code->qr_size;
PrintHorizontalLine(white, size);
int i = 0;
for (int y = 0; y < size; y++) {
fputs(white, stdout);
for (int x = 0; x < size; x++) {
fputs((code->data[i++] & 1) ? black : white, stdout);
}
fputs(white, stdout);
fputs("\n", stdout);
}
PrintHorizontalLine(white, size);
return 0;
}