summaryrefslogtreecommitdiff
path: root/src/escpos
diff options
context:
space:
mode:
Diffstat (limited to 'src/escpos')
-rw-r--r--src/escpos/parser.h6
-rw-r--r--src/escpos/parser.rl134
-rw-r--r--src/escpos/utf8.h37
3 files changed, 136 insertions, 41 deletions
diff --git a/src/escpos/parser.h b/src/escpos/parser.h
index 373a251..7b10ee9 100644
--- a/src/escpos/parser.h
+++ b/src/escpos/parser.h
@@ -4,6 +4,8 @@
#include <stdbool.h>
#include <stdint.h>
+#define ESCPOS_PRINT_BUFFER_MAX_HEIGHT 24
+
struct escpos_canvas {
uint8_t *data;
size_t w, h;
@@ -13,8 +15,8 @@ struct escpos_parser;
struct escpos_parser {
size_t (*read)(const struct escpos_parser *parser, void *ptr, const size_t size);
void (*write)(const struct escpos_parser *parser, const uint8_t *ptr, const size_t w, const size_t h);
- struct escpos_canvas canvas;
- struct escpos_mem window;
+ struct escpos_canvas canvas, print_buffer;
+ struct escpos_mem window, var;
};
bool
diff --git a/src/escpos/parser.rl b/src/escpos/parser.rl
index 1e045c7..015c690 100644
--- a/src/escpos/parser.rl
+++ b/src/escpos/parser.rl
@@ -7,6 +7,7 @@
#include <stdlib.h>
#include <assert.h>
#include <err.h>
+#include "utf8.h"
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
@@ -14,8 +15,15 @@
static const uint8_t SPACING = 1;
-struct raster {
+struct utf8 {
+ uint32_t state;
+};
+
+struct cursor {
size_t x, y, wy;
+};
+
+struct raster {
struct font font;
uint8_t barcode_height;
uint8_t barcode_type;
@@ -36,59 +44,91 @@ struct raster {
};
static void
-render_chr(struct escpos_canvas *canvas, struct raster *raster, const char chr)
+init_canvas(struct escpos_canvas *canvas, struct cursor *cursor)
+{
+ assert(canvas && cursor);
+ memset(canvas->data, 0, canvas->w * canvas->h);
+ *cursor = (struct cursor){ .x = 0, .y = 0, .wy = 0 };
+}
+
+static void
+init_raster(struct raster *raster)
+{
+ assert(raster);
+ *raster = (struct raster){ .font = _intlfonts_ucs };
+}
+
+static void
+render_chr(struct escpos_canvas *canvas, struct cursor *cursor, const struct raster *raster, const uint32_t cp)
{
assert(canvas && raster);
- const size_t off = canvas->w * raster->y + raster->x;
- const struct glyph *glyph = &raster->font.ucs2glyph[MIN((uint8_t)MAX(chr, 0), raster->font.max_ucs)];
+ const size_t off = canvas->w * cursor->y + cursor->x;
+ const struct glyph *glyph = &raster->font.ucs2glyph[MIN(MAX(cp, 0), raster->font.max_ucs)];
+ const size_t width = div_round_up(glyph->width, 8);
const uint8_t *data = &raster->font.data[glyph->offset];
for (size_t gy = 0; gy < raster->font.height; ++gy) {
- for (size_t gx = 0; gx < glyph->width; gx += 8) {
+ for (size_t gx = 0; gx < width; ++gx) {
for (uint8_t b = 0; b < 8; ++b) {
- const size_t dst = off + (canvas->w * gy + gx + b);
+ const size_t dst = off + (canvas->w * gy + (gx * 4) + b);
assert(dst < canvas->w * canvas->h);
- canvas->data[dst] = data[div_round_up(glyph->width, 8) * gy + gx] & (1 << (7 - b));
+ canvas->data[dst] = data[width * gy + gx] & (1 << (7 - b));
}
}
}
- raster->x += MIN(glyph->width + SPACING, canvas->w - raster->x);
- raster->wy = MIN(raster->y + MAX(raster->font.height, 1) - 1, canvas->h);
+ cursor->x += MIN(glyph->width + SPACING, canvas->w - cursor->x);
+ cursor->wy = MIN(cursor->y + MAX(raster->font.height, 1) - 1, canvas->h);
}
static void
-init(struct escpos_canvas *canvas, struct raster *raster)
+apply_canvas(struct escpos_canvas *dst, struct cursor *dst_cursor, struct escpos_canvas *src, struct cursor *src_cursor)
{
- assert(canvas && raster);
- memset(canvas->data, 0, canvas->w * canvas->h);
- *raster = (struct raster){ .font = _intlfonts_ucs };
- raster->x = raster->y = raster->wy = 0;
+ // According to epson docs, the justification is applied after print buffer is applied
+ // Thus we should apply justification here, need const struct *raster as input.
+ assert(dst && dst_cursor && src && src_cursor);
+ const size_t off = dst->w * dst_cursor->y + dst_cursor->x;
+ assert(off + src->w * src_cursor->wy <= dst->w * dst->h);
+ memcpy((char*)dst->data + off, src->data, src->w * src_cursor->wy);
+ dst_cursor->wy = MAX(dst_cursor->wy, src_cursor->wy);
+ init_canvas(src, src_cursor);
}
static void
-lfd(const struct escpos_canvas *canvas, struct raster *raster, const uint8_t num)
+render_checker(struct escpos_canvas *canvas)
{
- assert(canvas && raster);
+ for (size_t gy = 0; gy < canvas->w; ++gy) {
+ for (size_t gx = 0; gx < canvas->h; ++gx) {
+ const size_t dst = canvas->w * gy + gx;
+ assert(dst < canvas->w * canvas->h);
+ canvas->data[dst] = ((gy * gx) % 2);
+ }
+ }
+}
+
+static void
+lfd(const struct escpos_canvas *canvas, struct cursor *cursor, const struct raster *raster, const uint8_t num)
+{
+ assert(canvas && cursor);
const size_t lf = (raster->font.height + SPACING) * num;
- raster->x = 0;
- raster->y += MIN(lf, canvas->h - raster->y);
- raster->wy = raster->y + raster->font.height + SPACING;
+ cursor->x = 0;
+ cursor->y += MIN(lf, canvas->h - cursor->y);
+ cursor->wy = cursor->y + raster->font.height + SPACING;
}
static void
-cut(const struct escpos_parser *parser, struct escpos_canvas *canvas, struct raster *raster)
+cut(const struct escpos_parser *parser, struct escpos_canvas *canvas, struct cursor *cursor)
{
- assert(canvas && raster);
- assert(raster->wy <= canvas->h);
+ assert(parser && canvas && cursor);
+ assert(cursor->wy <= canvas->h);
- if (raster->wy > 0) {
- parser->write(parser, canvas->data, canvas->w, MIN(canvas->h, raster->wy));
- memset(canvas->data, 0, canvas->w * canvas->h);
- raster->x = raster->y = raster->wy = 0;
+ if (cursor->wy > 0) {
+ parser->write(parser, canvas->data, canvas->w, MIN(canvas->h, cursor->wy));
+ init_canvas(canvas, cursor);
}
}
%%{
machine escpos_parser;
+ alphtype unsigned char;
include escpos_stack "stack.rl";
variable p ragel.p;
variable pe ragel.pe;
@@ -97,20 +137,25 @@ cut(const struct escpos_parser *parser, struct escpos_canvas *canvas, struct ras
action init {
puts("init");
- init(&parser->canvas, &raster);
+ init_canvas(&parser->canvas, &canvas_cursor);
+ init_canvas(&parser->print_buffer, &print_buffer_cursor);
+ init_raster(&raster);
}
action lfd {
fprintf(stderr, "lfd %d\n", stack_get_num(&stack));
- lfd(&parser->canvas, &raster, stack_get_num(&stack));
+ apply_canvas(&parser->canvas, &canvas_cursor, &parser->print_buffer, &print_buffer_cursor);
+ lfd(&parser->canvas, &canvas_cursor, &raster, stack_get_num(&stack));
}
action lfv {
fprintf(stderr, "lfv %d\n", stack_get_num(&stack));
+ apply_canvas(&parser->canvas, &canvas_cursor, &parser->print_buffer, &print_buffer_cursor);
+ lfd(&parser->canvas, &canvas_cursor, &raster, stack_get_num(&stack));
const size_t lf = (raster.font.height + SPACING) * stack_get_num(&stack);
- raster.x = 0;
- raster.y -= MIN(lf, raster.y);
- raster.wy = raster.y + raster.font.height + SPACING;
+ canvas_cursor.x = 0;
+ canvas_cursor.y -= MIN(lf, canvas_cursor.y);
+ canvas_cursor.wy = canvas_cursor.y + raster.font.height + SPACING;
}
action print_mode {
@@ -137,7 +182,7 @@ cut(const struct escpos_parser *parser, struct escpos_canvas *canvas, struct ras
action cut {
fprintf(stderr, "cut %d\n", stack_get_num(&stack));
- cut(parser, &parser->canvas, &raster);
+ cut(parser, &parser->canvas, &canvas_cursor);
}
action emphasis {
@@ -181,13 +226,16 @@ cut(const struct escpos_parser *parser, struct escpos_canvas *canvas, struct ras
action text {
putc(fc, stderr);
- render_chr(&parser->canvas, &raster, fc);
+ uint32_t cp;
+ if (utf8_decode(&utf8.state, &cp, fc) == UTF8_ACCEPT)
+ render_chr(&parser->print_buffer, &print_buffer_cursor, &raster, cp);
}
action line {
fputs("\\n", stderr);
ragel_advance_line(&ragel);
- lfd(&parser->canvas, &raster, 1);
+ apply_canvas(&parser->canvas, &canvas_cursor, &parser->print_buffer, &print_buffer_cursor);
+ lfd(&parser->canvas, &canvas_cursor, &raster, 1);
}
# Constants
@@ -230,12 +278,18 @@ escpos_parser_parse(struct escpos_parser *parser, const char *name)
assert(parser->read);
assert(parser->write);
- char var[256];
- struct stack stack = { .var.buf.mem = { .data = var, .len = sizeof(var) } };
+ struct stack stack = { .var.buf.mem = parser->var };
struct ragel ragel = { .name = name, .lineno = 1 };
+ struct utf8 utf8 = {0};
+
+ struct cursor canvas_cursor, print_buffer_cursor;
+ init_canvas(&parser->canvas, &canvas_cursor);
+ init_canvas(&parser->print_buffer, &print_buffer_cursor);
struct raster raster;
- init(&parser->canvas, &raster);
+ init_raster(&raster);
+
+ // render_checker(&parser->canvas, &canvas_cursor);
struct escpos_mem window = parser->window;
for (bool eof = false; !ragel.error && !eof;) {
@@ -245,8 +299,10 @@ escpos_parser_parse(struct escpos_parser *parser, const char *name)
%% write exec;
}
- if (!ragel.error)
- cut(parser, &parser->canvas, &raster);
+ if (!ragel.error) {
+ apply_canvas(&parser->canvas, &canvas_cursor, &parser->print_buffer, &print_buffer_cursor);
+ cut(parser, &parser->canvas, &canvas_cursor);
+ }
return !ragel.error;
}
diff --git a/src/escpos/utf8.h b/src/escpos/utf8.h
new file mode 100644
index 0000000..744f294
--- /dev/null
+++ b/src/escpos/utf8.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include <stdint.h>
+#include <assert.h>
+
+// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
+// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
+
+#define UTF8_ACCEPT 0
+#define UTF8_REJECT 1
+
+static const uint8_t utf8d[] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
+ 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
+ 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
+ 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
+ 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
+ 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
+ 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
+ 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
+};
+
+static inline uint32_t
+utf8_decode(uint32_t* state, uint32_t* codep, uint8_t byte)
+{
+ assert(state && codep);
+ const uint32_t type = utf8d[byte];
+ *codep = (*state != UTF8_ACCEPT) ? (byte & 0x3fu) | (*codep << 6) : (0xff >> type) & (byte);
+ *state = utf8d[256 + *state*16 + type];
+ return *state;
+}