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

print_output.h

v0.1.0-build.85 Latest Commit ede38f5

Size
5.0 KB
Lines
76
Language
cpp
SHA-256
64eb2f23b59a…
View on GitHub

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

1// Print output for the CLI: 1-bit PNG on the printer's exact dot grid (no
2// anti-aliasing, so no grey for the printer to halftone into noise), with a
3// pHYs chunk so the image prints at its true physical size, plus a tiny 5x7
4// bitmap font for calibration-sheet labels. Uses only the core's C ABI.
5#ifndef CKEY_CLI_PRINT_OUTPUT_H
6#define CKEY_CLI_PRINT_OUTPUT_H
7
8#include "ckey/ckey.h"
9
10#include <array>
11#include <cstdint>
12#include <fstream>
13#include <map>
14#include <string>
15#include <vector>
16
17namespace printout {
18
19struct Page { int width = 0, height = 0; std::vector<uint8_t> ink; }; // 1 = ink
20
21// 1-bit PNG with pHYs, through the core's PNG encoder.
22inline bool write_png(const std::string &path, const Page &page, double dpi) {
23 std::vector<uint8_t> gray(page.ink.size());
24 for (size_t i = 0; i < gray.size(); ++i) gray[i] = page.ink[i] ? 0 : 255;
25 size_t need = 0;
26 if (ckey_encode_png(gray.data(), static_cast<uint32_t>(page.width), static_cast<uint32_t>(page.height), 0, CKEY_PNG_GRAY1, dpi, nullptr, 0, &need) != CKEY_INSUFFICIENT_BUFFER) return false;
27 std::vector<uint8_t> png(need);
28 if (ckey_encode_png(gray.data(), static_cast<uint32_t>(page.width), static_cast<uint32_t>(page.height), 0, CKEY_PNG_GRAY1, dpi, png.data(), png.size(), &need) != CKEY_OK) return false;
29 std::ofstream out(path, std::ios::binary); if (!out) return false;
30 out.write(reinterpret_cast<const char *>(png.data()), static_cast<std::streamsize>(png.size()));
31 return static_cast<bool>(out);
32}
33
34// Draws a Profile 0 symbol as black ink on paper at a physical width (the
35// 31-unit canvas including its quiet margin) on the device dot grid, with
36// the core's direct print rasterizer.
37inline bool draw_symbol(Page &page, const ckey_scalable_symbol &symbol, const ckey_style *style, int x0, int y0, int side_px, double dpi) {
38 size_t side = 0;
39 if (ckey_render_scalable_print(&symbol, style, side_px / dpi, dpi, nullptr, 0, &side) != CKEY_INSUFFICIENT_BUFFER) return false;
40 std::vector<uint8_t> px(side * side);
41 if (ckey_render_scalable_print(&symbol, style, side_px / dpi, dpi, px.data(), px.size(), &side) != CKEY_OK) return false;
42 for (size_t y = 0; y < side; ++y) for (size_t x = 0; x < side; ++x) {
43 const long px_x = x0 + static_cast<long>(x), px_y = y0 + static_cast<long>(y);
44 if (px_x >= 0 && px_y >= 0 && px_x < page.width && px_y < page.height && px[y * side + x] == 0)
45 page.ink[static_cast<size_t>(px_y) * page.width + px_x] = 1;
46 }
47 return true;
48}
49
50inline void draw_text(Page &page, const std::string &text, int x, int y, int scale) {
51 static const std::map<char, std::array<uint8_t, 7>> font = {
52 {'0', {14, 17, 19, 21, 25, 17, 14}}, {'1', {4, 12, 4, 4, 4, 4, 14}}, {'2', {14, 17, 1, 2, 4, 8, 31}}, {'3', {31, 2, 4, 2, 1, 17, 14}},
53 {'4', {2, 6, 10, 18, 31, 2, 2}}, {'5', {31, 16, 30, 1, 1, 17, 14}}, {'6', {6, 8, 16, 30, 17, 17, 14}}, {'7', {31, 1, 2, 4, 8, 8, 8}},
54 {'8', {14, 17, 17, 14, 17, 17, 14}}, {'9', {14, 17, 17, 15, 1, 2, 12}}, {'.', {0, 0, 0, 0, 0, 12, 12}}, {' ', {0, 0, 0, 0, 0, 0, 0}},
55 {'P', {30, 17, 17, 30, 16, 16, 16}}, {'v', {0, 0, 17, 17, 17, 10, 4}}, {'B', {30, 17, 17, 30, 17, 17, 30}}, {'i', {4, 0, 12, 4, 4, 4, 14}},
56 {'n', {0, 0, 22, 25, 17, 17, 17}}, {'M', {17, 27, 21, 21, 17, 17, 17}}, {'d', {1, 1, 13, 19, 17, 17, 15}}, {'p', {0, 0, 30, 17, 30, 16, 16}},
57 {'C', {14, 17, 16, 16, 16, 17, 14}}, {'K', {17, 18, 20, 24, 20, 18, 17}}, {'e', {0, 0, 14, 17, 31, 16, 14}}, {'y', {0, 0, 17, 17, 15, 1, 14}},
58 {'r', {0, 0, 22, 25, 16, 16, 16}}, {'t', {8, 8, 28, 8, 8, 9, 6}}, {'a', {0, 0, 14, 1, 15, 17, 15}}, {'s', {0, 0, 15, 16, 14, 1, 30}},
59 {'l', {12, 4, 4, 4, 4, 4, 14}}, {'o', {0, 0, 14, 17, 17, 17, 14}}, {'g', {0, 0, 15, 17, 15, 1, 14}}, {'@', {14, 17, 23, 21, 23, 16, 15}},
60 {'-', {0, 0, 0, 31, 0, 0, 0}}, {'h', {16, 16, 22, 25, 17, 17, 17}}, {'c', {0, 0, 14, 16, 16, 17, 14}}, {'b', {16, 16, 22, 25, 17, 17, 30}},
61 {'L', {16, 16, 16, 16, 16, 16, 31}}, {'S', {15, 16, 16, 14, 1, 1, 30}}, {'A', {14, 17, 17, 31, 17, 17, 17}}, {'D', {28, 18, 17, 17, 17, 18, 28}},
62 {'I', {14, 4, 4, 4, 4, 4, 14}}, {'x', {0, 0, 17, 10, 4, 10, 17}}, {'m', {0, 0, 26, 21, 21, 17, 17}}, {'u', {0, 0, 17, 17, 17, 19, 13}},
63 {'f', {6, 9, 8, 28, 8, 8, 8}}, {'%', {24, 25, 2, 4, 8, 19, 3}}, {'z', {0, 0, 31, 2, 4, 8, 31}}, {'/', {1, 1, 2, 4, 8, 16, 16}}, {'k', {16, 16, 18, 20, 24, 20, 18}}, {'w', {0, 0, 17, 17, 21, 21, 10}}, {'=', {0, 0, 31, 0, 31, 0, 0}}};
64 for (char ch : text) {
65 const auto it = font.find(ch);
66 if (it != font.end()) for (int r = 0; r < 7; ++r) for (int c = 0; c < 5; ++c) if (it->second[r] & (16 >> c))
67 for (int dy = 0; dy < scale; ++dy) for (int dx = 0; dx < scale; ++dx) {
68 const int px = x + c * scale + dx, py = y + r * scale + dy;
69 if (px >= 0 && py >= 0 && px < page.width && py < page.height) page.ink[static_cast<size_t>(py) * page.width + px] = 1;
70 }
71 x += 6 * scale;
72 }
73}
74
75} // namespace printout
76#endif