summaryrefslogtreecommitdiff
path: root/src/bin
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/escpos2raster.c80
-rw-r--r--src/bin/starpbm.c153
2 files changed, 233 insertions, 0 deletions
diff --git a/src/bin/escpos2raster.c b/src/bin/escpos2raster.c
new file mode 100644
index 0000000..e4c9708
--- /dev/null
+++ b/src/bin/escpos2raster.c
@@ -0,0 +1,80 @@
+#include <escpos/parser.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <err.h>
+
+static FILE*
+fopen_or_die(const char *path, const char *mode)
+{
+ assert(path && mode);
+
+ FILE *f;
+ if (!(f = fopen(path, mode)))
+ err(EXIT_FAILURE, "fopen(%s, %s)", path, mode);
+
+ return f;
+}
+
+struct parser {
+ struct escpos_parser parser;
+ FILE *input, *output;
+};
+
+#define container_of(ptr, type, member) ((type *)((char *)(1 ? (ptr) : &((type *)0)->member) - offsetof(type, member)))
+
+size_t
+escpos_read(const struct escpos_parser *parser, void *ptr, const size_t size)
+{
+ assert(parser && ptr);
+ const struct parser *p = container_of(parser, struct parser, parser);
+ return fread(ptr, 1, size, p->input);
+}
+
+void
+escpos_write(const struct escpos_parser *parser, const uint8_t *ptr, const size_t w, const size_t h)
+{
+ assert(parser && ptr);
+ const struct parser *p = container_of(parser, struct parser, parser);
+ const uint8_t header[] = { 'P', '4', '\n' };
+ fwrite(header, 1, sizeof(header), p->output);
+ fprintf(p->output, "%zu\n", w);
+ fprintf(p->output, "%zu\n", h);
+ for (size_t y = 0; y < h; ++y) {
+ for (size_t x = 0; x < w; x += 8) {
+ uint8_t p8 = 255;
+ for (uint8_t b = 0; b < 8 && x + b < w; ++b)
+ p8 ^= (-(!!ptr[y * w + x + b]) ^ p8) & (1 << (7 - b));
+ fwrite(&p8, 1, 1, p->output);
+ }
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ {
+#define CANVAS_W 256
+#define CANVAS_H 1024
+ char window[4096];
+ uint8_t canvas_data[CANVAS_W * CANVAS_H];
+ struct parser p = {
+ .parser = {
+ .read = escpos_read,
+ .write = escpos_write,
+ .canvas = { .data = canvas_data, .w = CANVAS_W, .h = CANVAS_H },
+ .window = { .data = window, sizeof(window) },
+ },
+ .input = (argc >= 2 ? fopen_or_die(argv[1], "rb") : stdin),
+ .output = (argc >= 3 ? fopen_or_die(argv[2], "wb") : stdout),
+ };
+
+ if (!escpos_parser_parse(&p.parser, (argc >= 2 ? argv[1] : "stdin")))
+ exit(EXIT_FAILURE);
+
+ fclose(p.input);
+ fclose(p.output);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/bin/starpbm.c b/src/bin/starpbm.c
new file mode 100644
index 0000000..fd3f235
--- /dev/null
+++ b/src/bin/starpbm.c
@@ -0,0 +1,153 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <err.h>
+
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+
+enum cmd {
+ CMD_INIT,
+ CMD_PRINTABLE_WIDTH,
+ CMD_RASTER_MODE_START,
+ CMD_RASTER_PAGE_LENGTH,
+ CMD_START_PAGE,
+ CMD_END_PAGE,
+ CMD_END_JOB,
+};
+
+static void
+putcmd(FILE *f, const enum cmd cmd)
+{
+ assert(f);
+
+ const struct {
+ const uint8_t *bytes;
+ size_t len;
+ } map[] = {
+#define CMD(...) { .bytes = (uint8_t[]){__VA_ARGS__ }, .len = sizeof((uint8_t[]){__VA_ARGS__}) }
+ CMD(0x1b, '@'), // CMD_INIT
+ CMD(0x1b, 0x1e, 'A', 0x00), // CMD_PRINTABLE_WIDTH
+ CMD(0x1b, '*', 'r', 'R', 0x1b, '*', 'r', 'A'), // CMD_RASTER_MODE_START
+ CMD(0x1b, '*', 'r', 'P', '0', 0x00), // CMD_SET_RASTER_PAGE_LENGTH
+ CMD(0x00), // CMD_START_PAGE
+ CMD(0x1b, '*', 'r', 'Y', '1', 0x00, 0x1b, 0x0c), // CMD_END_PAGE
+ CMD(0x04, 0x1b, '*', 'r', 'B'), // CMD_END_JOB
+#undef CMD
+ };
+
+ if (fwrite(map[cmd].bytes, 1, map[cmd].len, f) != map[cmd].len)
+ err(EXIT_FAILURE, "fwrite");
+}
+
+static FILE*
+fopen_or_die(const char *path, const char *mode)
+{
+ assert(path && mode);
+
+ FILE *f;
+ if (!(f = fopen(path, mode)))
+ err(EXIT_FAILURE, "fopen(%s, %s)", path, mode);
+
+ return f;
+}
+
+static uint8_t*
+find_pixel_not_rev(const uint8_t *data, const size_t len, const uint8_t pixel)
+{
+ for (const uint8_t *p = data + MAX(len, 1) - 1; p != data; --p) {
+ if (*p != pixel)
+ return (uint8_t*)p;
+ }
+ return NULL;
+}
+
+uint8_t*
+pixels_from_pbm(FILE *f, size_t *out_w, size_t *out_h)
+{
+ // NOTE: This does not support comments or extra whitespaces
+ // Assumes PBM is structured!
+
+ uint8_t magic[3];
+ if (fread(magic, 1, sizeof(magic), f) != sizeof(magic))
+ return NULL;
+
+ if (memcmp(magic, "P4", 2) || !isspace(magic[2]))
+ errx(EXIT_FAILURE, "not a valid pbm (P4) file");
+
+ uint32_t cfg[2];
+ for (uint8_t i = 0; i < sizeof(cfg) / sizeof(cfg[0]); ++i) {
+ char buf[32];
+ size_t x = 0;
+ do {
+ if (fread(buf + x, 1, 1, f) != 1)
+ err(EXIT_FAILURE, "fread");
+ } while (!isspace(buf[x]) && ++x < sizeof(buf));
+
+ if (!isspace(buf[x]))
+ errx(EXIT_FAILURE, "not a valid pbm (P4) file");
+
+ cfg[i] = strtol(buf, NULL, 10);
+ }
+
+ if (!cfg[0] || !cfg[2])
+ errx(EXIT_FAILURE, "invalid width / height");
+
+ uint8_t *bw;
+#define div_round_up(x, y) (1 + ((x - 1) / y))
+ const size_t bw_sz = div_round_up(cfg[0], 8) * cfg[1];
+ if (!(bw = calloc(bw_sz, 1)))
+ err(EXIT_FAILURE, "calloc");
+
+ for (size_t read = 0, r; read < bw_sz; read += r) {
+ if (!(r = fread(bw + read, 1, bw_sz - read, f)))
+ errx(EXIT_FAILURE, "fread");
+ }
+
+ *out_w = div_round_up(cfg[0], 8), *out_h = cfg[1];
+ return bw;
+}
+
+int
+main(int argc, char *argv[])
+{
+ FILE *input = (argc >= 2 ? fopen_or_die(argv[1], "rb") : stdin);
+ FILE *output = (argc >= 3 ? fopen_or_die(argv[2], "wb") : stdout);
+
+ putcmd(output, CMD_INIT);
+ putcmd(output, CMD_PRINTABLE_WIDTH);
+ putcmd(output, CMD_RASTER_MODE_START);
+ putcmd(output, CMD_RASTER_PAGE_LENGTH);
+
+ size_t w, h;
+ uint8_t *pixels;
+ while ((pixels = pixels_from_pbm(input, &w, &h))) {
+ putcmd(output, CMD_START_PAGE);
+
+ size_t blank = 0;
+ for (size_t y = 0; y < h; ++y) {
+ const uint8_t *last_black;
+ if (!(last_black = find_pixel_not_rev(&pixels[y * w], w, 0))) {
+ ++blank;
+ continue;
+ }
+
+ if (blank) {
+ fprintf(output, "\x01b*rY%zu%c", blank, 0);
+ blank = 0;
+ }
+
+ const size_t pos = (last_black - &pixels[y * w]) + 1;
+ fprintf(output, "b%c%c", (char)(pos % 256), (char)(pos / 256));
+ fwrite(&pixels[y * w], 1, pos, output);
+ }
+
+ putcmd(output, CMD_END_PAGE);
+ free(pixels);
+ }
+
+ putcmd(output, CMD_END_JOB);
+ return EXIT_SUCCESS;
+}