diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/bin/escpos2raster.c | 10 | ||||
-rw-r--r-- | src/escpos/parser.h | 6 | ||||
-rw-r--r-- | src/escpos/parser.rl | 134 | ||||
-rw-r--r-- | src/escpos/utf8.h | 37 |
5 files changed, 143 insertions, 46 deletions
@@ -26,7 +26,7 @@ $(bins): %: escpos-membuf.a: src/escpos/memory.h src/util/membuf.h src/util/membuf.c escpos-ragel.a: src/util/ragel/ragel.h src/util/ragel/ragel.c escpos-stack.a: src/escpos/stack.h src/escpos/stack.c -escpos-parser.a: src/escpos/parser.h src/escpos/parser.c +escpos-parser.a: src/escpos/parser.h src/escpos/parser.c src/escpos/utf8.h escpos-stack.a escpos2raster: src/bin/escpos2raster.c escpos-membuf.a escpos-ragel.a escpos-stack.a escpos-parser.a starpbm: src/bin/starpbm.c diff --git a/src/bin/escpos2raster.c b/src/bin/escpos2raster.c index e4c9708..4eaafe1 100644 --- a/src/bin/escpos2raster.c +++ b/src/bin/escpos2raster.c @@ -54,16 +54,18 @@ int main(int argc, char *argv[]) { { -#define CANVAS_W 256 +#define CANVAS_W 267 * 2 #define CANVAS_H 1024 - char window[4096]; - uint8_t canvas_data[CANVAS_W * CANVAS_H]; + char window[4096], var[256]; + uint8_t canvas_data[CANVAS_W * CANVAS_H], print_buffer[CANVAS_W * ESCPOS_PRINT_BUFFER_MAX_HEIGHT]; 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) }, + .print_buffer = { .data = print_buffer, .w = CANVAS_W, .h = ESCPOS_PRINT_BUFFER_MAX_HEIGHT }, + .window = { .data = window, .len = sizeof(window) }, + .var = { .data = var, .len = sizeof(var) }, }, .input = (argc >= 2 ? fopen_or_die(argv[1], "rb") : stdin), .output = (argc >= 3 ? fopen_or_die(argv[2], "wb") : stdout), 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; +} |