Viewing is open to everyone. Downloading and starring need a GitHub sign-in. Sign in with GitHub

ckey_gallery.cpp

v0.1.0-build.85 Latest Commit ede38f5

Size
8.7 KB
Lines
181
Language
cpp
SHA-256
fcb9935ccf7a…
View on GitHub

Sign in with GitHub to download. Each download is recorded with your GitHub username.

1// Renders the example symbols in docs/gallery: each one is drawn with the
2// public API, read back with the real decoder, and certified. Writes one
3// PNG per entry plus docs/gallery/README.md.
4//
5// cmake --build build --target ckey-gallery
6// ./build/ckey-gallery docs/gallery
7#include <ckey/ckey.h>
8#include <cstdio>
9#include <cstring>
10#include <functional>
11#include <string>
12#include <vector>
13
14namespace {
15
16struct Entry {
17 const char *file;
18 const char *title;
19 const char *about;
20 std::string payload;
21 uint32_t version; // 0 = smallest that fits
22 ckey_ecc_level level;
23 ckey_scalable_layout layout;
24 std::function<void(ckey_style &)> style;
25};
26
27ckey_rgb hex(uint32_t v) { return ckey_rgb{uint8_t(v >> 16), uint8_t(v >> 8), uint8_t(v)}; }
28
29bool write_file(const std::string &path, const std::vector<uint8_t> &bytes) {
30 FILE *f = std::fopen(path.c_str(), "wb");
31 if (!f) return false;
32 const bool ok = std::fwrite(bytes.data(), 1, bytes.size(), f) == bytes.size();
33 return std::fclose(f) == 0 && ok;
34}
35
36// Reads the symbol back from a GRAY8 rendering with the reader pipeline.
37bool reads_back(const ckey_scalable_symbol &symbol, const ckey_style &style, const std::string &expected) {
38 const uint32_t size = 768;
39 ckey_raster_options options;
40 ckey_raster_options_default(&options);
41 options.size_px = size;
42 options.format = CKEY_PIXELS_GRAY8;
43 std::vector<uint8_t> gray(size_t(size) * size);
44 size_t needed = 0;
45 if (ckey_render_scalable_raster(&symbol, &style, &options, gray.data(), gray.size(), &needed) != CKEY_OK) return false;
46 double borders[8 * 8];
47 double quad[8];
48 const size_t found = ckey_find_borders_gray8(gray.data(), size, size, size, borders, 8);
49 std::vector<uint8_t> out(65535);
50 for (size_t i = 0; i < found; ++i) {
51 size_t len = 0;
52 uint32_t version = 0;
53 ckey_diagnostics diag{};
54 if (ckey_refine_quad_gray8(gray.data(), size, size, size, borders + 8 * i, CKEY_FIELD_SCALABLE, quad) > 0 &&
55 ckey_decode_scalable_gray8(gray.data(), size, size, size, quad, out.data(), out.size(), &len, &version,
56 nullptr, &diag) == CKEY_OK)
57 return std::string(reinterpret_cast<const char *>(out.data()), len) == expected;
58 }
59 return false;
60}
61
62std::string grade_of(const char *message) {
63 for (const char *g : {"excellent", "good", "marginal", "fails"}) {
64 const std::string token = std::string(g) + " scan margin";
65 if (std::strstr(message, token.c_str())) return g;
66 }
67 return "n/a";
68}
69
70} // namespace
71
72int main(int argc, char **argv) {
73 const std::string dir = argc > 1 ? argv[1] : "docs/gallery";
74 const std::string license_excerpt =
75 "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and "
76 "associated documentation files (the \"Software\"), to deal in the Software without restriction, including "
77 "without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell "
78 "copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the "
79 "following conditions: The above copyright notice and this permission notice shall be included in all "
80 "copies or substantial portions of the Software.";
81 const std::string vcard =
82 "BEGIN:VCARD\nVERSION:3.0\nN:Hart;Amelia;;Dr.;\nFN:Dr. Amelia Hart\nORG:Cardiology\nTEL:+15550100\nEND:VCARD";
83
84 const std::vector<Entry> entries = {
85 {"link-plain.png", "A link, plain", "The default style: black on white.", "https://openckey.org", 0,
86 CKEY_ECC_M, CKEY_LAYOUT_STANDARD, [](ckey_style &) {}},
87 {"link-print.png", "A link, print layout (Profile 0.1)", "Larger marks and gaps for small printed labels.",
88 "https://openckey.org", 0, CKEY_ECC_M, CKEY_LAYOUT_PRINT, [](ckey_style &) {}},
89 {"contact-evergreen.png", "A contact card, evergreen on paper", "Custom ink and background.", vcard, 0,
90 CKEY_ECC_M, CKEY_LAYOUT_STANDARD,
91 [](ckey_style &s) {
92 s.ink = s.ink_shade = hex(0x215D3B);
93 s.background = s.background_edge = hex(0xFCFAF6);
94 }},
95 {"concept.png", "The Concept preset", "Cream metallic ink on a dark vignette, with accents, depth and grain.",
96 "https://openckey.org/about", 0, CKEY_ECC_Q, CKEY_LAYOUT_STANDARD,
97 [](ckey_style &s) { ckey_style_preset_fill(&s, CKEY_PRESET_CONCEPT); }},
98 {"dots-navy.png", "Dotted rings, circle modules", "Ring marks drawn as separate dots, circular modules.",
99 "Visiting hours: 8 am to 8 pm, every day.", 0, CKEY_ECC_M, CKEY_LAYOUT_STANDARD,
100 [](ckey_style &s) {
101 s.rings = CKEY_RING_DOTS;
102 s.modules = CKEY_MODULE_CIRCLE;
103 s.rays = CKEY_RAY_FLAT;
104 s.ink = s.ink_shade = hex(0x1C2B4A);
105 }},
106 {"accents.png", "Accent colours", "A share of the data marks drawn in accent colours.",
107 "https://openckey.org/scan", 0, CKEY_ECC_M, CKEY_LAYOUT_STANDARD,
108 [](ckey_style &s) {
109 s.accents[0] = hex(0x9A3130);
110 s.accents[1] = hex(0x215D3B);
111 s.accent_count = 2;
112 s.accent_percent = 35;
113 }},
114 {"dark.png", "Light on dark", "Paper-coloured ink on an ink-coloured background.", "https://openckey.org",
115 0, CKEY_ECC_M, CKEY_LAYOUT_STANDARD,
116 [](ckey_style &s) {
117 s.ink = s.ink_shade = hex(0xFCFAF6);
118 s.background = s.background_edge = hex(0x18211A);
119 }},
120 {"dense.png", "A dense symbol", "About 560 bytes of text at level M.", license_excerpt, 0, CKEY_ECC_M,
121 CKEY_LAYOUT_STANDARD, [](ckey_style &) {}},
122 };
123
124 std::string md =
125 "# Gallery\n\n"
126 "Every image here is rendered by the CKey core with `tools/gallery/ckey_gallery.cpp`, read back with the "
127 "real decoder, and certified with the modelled photo sweep (a model, not a measurement). Rebuild them "
128 "with:\n\n```sh\ncmake --build build --target ckey-gallery\n./build/ckey-gallery docs/gallery\n```\n\n"
129 "| | Symbol | Holds | Version | Reads back | Certification |\n|---|---|---|---|---|---|\n";
130 int failures = 0;
131 for (const Entry &e : entries) {
132 ckey_scalable_symbol symbol{};
133 ckey_diagnostics diag{};
134 if (ckey_encode_scalable(reinterpret_cast<const uint8_t *>(e.payload.data()), e.payload.size(), e.version,
135 e.level, e.layout, &symbol, &diag) != CKEY_OK) {
136 std::fprintf(stderr, "%s: encode failed: %s\n", e.file, diag.message);
137 return 1;
138 }
139 ckey_style style;
140 ckey_style_default(&style);
141 e.style(style);
142
143 const uint32_t size = 640;
144 ckey_raster_options options;
145 ckey_raster_options_default(&options);
146 options.size_px = size;
147 std::vector<uint8_t> rgba(size_t(size) * size * 4);
148 size_t needed = 0;
149 if (ckey_render_scalable_raster(&symbol, &style, &options, rgba.data(), rgba.size(), &needed) != CKEY_OK) {
150 std::fprintf(stderr, "%s: render refused\n", e.file);
151 return 1;
152 }
153 ckey_encode_png(rgba.data(), size, size, 0, CKEY_PNG_RGBA8, 0, nullptr, 0, &needed);
154 std::vector<uint8_t> png(needed);
155 if (ckey_encode_png(rgba.data(), size, size, 0, CKEY_PNG_RGBA8, 0, png.data(), png.size(), &needed) != CKEY_OK ||
156 !write_file(dir + "/" + e.file, png)) {
157 std::fprintf(stderr, "%s: could not write PNG\n", e.file);
158 return 1;
159 }
160
161 const bool read = reads_back(symbol, style, e.payload);
162 ckey_style adapted{};
163 ckey_certification report{};
164 ckey_certify_scalable_style(&symbol, &style, 0, nullptr, nullptr, &adapted, &report);
165 const std::string grade = report.certified ? "certified, " + grade_of(report.message) : "not certified (" + grade_of(report.message) + ")";
166 if (!read) ++failures;
167
168 char version[48];
169 std::snprintf(version, sizeof version, "%u%s", symbol.version, e.layout == CKEY_LAYOUT_PRINT ? " (print)" : "");
170 md += "| <img src=\"" + std::string(e.file) + "\" width=\"180\" alt=\"" + e.title + "\"> | **" + e.title +
171 "**<br>" + e.about + " | " + std::to_string(e.payload.size()) + " bytes | " + version + " | " +
172 (read ? "yes" : "**no**") + " | " + grade + " |\n";
173 std::printf("%-22s v%-3u %4zu bytes read=%s %s\n", e.file, symbol.version, e.payload.size(),
174 read ? "yes" : "NO", grade.c_str());
175 }
176 md += "\nCKey ";
177 md += ckey_get_software_version();
178 md += ".\n";
179 write_file(dir + "/README.md", std::vector<uint8_t>(md.begin(), md.end()));
180 return failures == 0 ? 0 : 2;
181}