diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | ql570.c | 226 |
2 files changed, 230 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c2ad0b4 --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +CFLAGS=-g +CFLAGS+= $(shell pkg-config --cflags libpng) +LDFLAGS+= $(shell pkg-config --libs libpng) +all: ql570 @@ -0,0 +1,226 @@ +/* + * Brother QL-570 thermal printing program + * It prints a mono PNG image directly to the printers block device + * + * Copyright 2011 Asbjørn Sloth Tønnesen <code@asbjorn.it> + * + * PNG reading based on: + * A simple libpng example program + * http://zarb.org/~gc/html/libpng.html + * Copyright 2002-2011 Guillaume Cottenceau and contributors. + * + * This software may be freely redistributed under the terms + * of the libpng license. + * http://libpng.org/pub/png/src/libpng-LICENSE.txt + * + * Example usage: + * ./ql570 /dev/usb/lp0 image.png + */ + +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <errno.h> + +#define PNG_DEBUG 3 +#include <png.h> + +#define ESC 0x1b + +#define DEBUG + +FILE * fp; + +struct { + int16_t w; + int16_t h; + uint8_t * data; +} typedef pngdata_t; + +FILE * ql570_open(const char * path) +{ + fp = fopen(path, "r+b"); + if (fp == NULL) { + perror("fopen"); + exit(EXIT_FAILURE); + } + return fp; +} + +void check_img(pngdata_t * img) +{ + int i, j; + int lb = (img->w / 8) + (img->w % 8 > 0); + printf("lb: %d\n", lb); + for (i=0;i<img->h;i++) { + for (j=img->w-1;j!=0;j--) { + if (img->data[i*lb+j/8] & (1 << (7-(j % 8)))) { + printf("#"); + } else { + printf(" "); + } + } + printf("\n"); + } + +} + +void ql570_print(pngdata_t * img) +{ + /* Init */ + fprintf(fp, "%c%c", ESC, '@'); + + /* Set media type */ + fprintf(fp, "%c%c%c%c%c%c%c%c%c%c%c%c%c", ESC, 'i', 'z', 0xa6, 0x0a, 29, 0, img->h & 0xff, img->h >> 8, 0, 0, 0, 0); + + /* Set cut type */ + fprintf(fp, "%c%c%c", ESC, 'i', 'K', 8); + + /* Enable cutter */ + fprintf(fp, "%c%c%c", ESC, 'i', 'A', 1); + + /* Set margin = 0 */ + fprintf(fp, "%c%c%c%c%c", ESC, 'i', 'd', 0, 0); + + int i, j; + int lb = (img->w / 8) + (img->w % 8 > 0); + for (i=0;i<img->h;i++) { + fprintf(fp, "%c%c%c", 'g', 0x00, 90); + for (j=0;j<lb;j++) { + fprintf(fp, "%c", img->data[i*lb+j]); + } + for (;j<90;j++) { + fprintf(fp, "%c", 0x00); + } + } + + /* Print */ + fprintf(fp, "%c", 0x1a); +} + +void abort_(const char * s, ...) +{ + va_list args; + va_start(args, s); + vfprintf(stderr, s, args); + fprintf(stderr, "\n"); + va_end(args); + abort(); +} + +pngdata_t * loadpng(const char * path) +{ + png_structp png_ptr; + png_infop info_ptr; + png_bytep * row_pointers; + int width, height, rowbytes; + int x, y; + unsigned char header[8]; // 8 is the maximum size that can be checked + png_byte* ptr; + FILE *fp; + int type = 0; + int lb; + uint8_t * bitmap; + + /* open file and test for it being a png */ + fp = fopen(path, "rb"); + if (!fp) + abort_("[read_png_file] File %s could not be opened for reading", path); + fread(header, 1, 8, fp); + if (png_sig_cmp(header, 0, 8)) + abort_("[read_png_file] File %s is not recognized as a PNG file", path); + + /* initialize stuff */ + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + if (!png_ptr) + abort_("[read_png_file] png_create_read_struct failed"); + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + abort_("[read_png_file] png_create_info_struct failed"); + + if (setjmp(png_jmpbuf(png_ptr))) + abort_("[read_png_file] Error during init_io"); + + png_init_io(png_ptr, fp); + png_set_sig_bytes(png_ptr, 8); + + png_read_info(png_ptr, info_ptr); + + if (png_get_channels(png_ptr, info_ptr) == 1 + && png_get_bit_depth(png_ptr, info_ptr) == 1) { + type = 1; + } else if (png_get_channels(png_ptr, info_ptr) == 4 + && png_get_bit_depth(png_ptr, info_ptr) == 8) { + type = 2; + } + + if (type == 0) { + fprintf(stderr, "Invalid PNG! Only mono or 4x8-bit RGBA PNG files are allowed\n"); + exit(1); + } + + width = png_get_image_width(png_ptr, info_ptr); + height = png_get_image_height(png_ptr, info_ptr); + + png_read_update_info(png_ptr, info_ptr); + + /* read file */ + if (setjmp(png_jmpbuf(png_ptr))) + abort_("[read_png_file] Error during read_image"); + + row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); + + rowbytes = type == 1 ? (width / 8) + (width % 8 > 0) : width << 2; + + for (y=0; y<height; y++) + row_pointers[y] = (png_byte*) malloc(rowbytes); + + png_read_image(png_ptr, row_pointers); + + fclose(fp); + + lb = (height / 8) + (height % 8 > 0); + bitmap = malloc(width*lb); + memset(bitmap, 0, width*lb); + + #define heat_on(x, y) bitmap[(x*lb)+(y/8)] |= 1 << (7-(y%8)) + for (y=0; y<height; y++) { + png_byte* row = row_pointers[y]; + for (x=0; x<width; x++) { + if (type == 1) { + ptr = &(row[x/8]); + } else { + ptr = &(row[x<<2]); + } + if ((ptr[0] & (1 << (7-(x%8)))) == 0) { + heat_on(x, y); + } + } + } + + + pngdata_t * ret = malloc(sizeof(pngdata_t)); + ret->w = height; + ret->h = width; + ret->data = bitmap; + return ret; +} + +int main(int argc, const char ** argv) +{ + if (argc <= 2) { + fprintf(stderr, "Usage: %s printer pngfile\n", argv[0]); + exit(EXIT_FAILURE); + } + + ql570_open(argv[1]); + pngdata_t * data = loadpng(argv[2]); + //check_img(data); + printf("w: %d\th: %d\n", data->w, data->h); + //check_img(data); + ql570_print(data); + return EXIT_SUCCESS; +} |