You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

341 lines
8.2 KiB

// To get required headers, run
// sudo apt-get install libcups2-dev libcupsimage2-dev
#include <cups/cups.h>
#include <cups/ppd.h>
#include <cups/raster.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#ifndef DEBUGFILE
#define DEBUGFILE "/tmp/debugraster.txt"
#endif
struct settings_ {
int cashDrawer1;
int cashDrawer2;
int blankSpace;
int feedDist;
};
struct settings_ settings;
struct command {
int length;
char *command;
};
/*
* zj uses kind of epson ESC/P dialect code. Here is subset of commands
*
* initialize - esc @
* cash drawer 1 - esc p 0 @ P
* cash drawer 2 - esc p 1 @ P
* start raster - esc v 0
* skip lines - esc j
* cut - esc i
*/
// define printer initialize command
static const struct command printerInitializeCommand = {2,
(char[2]){0x1b, 0x40}}; // esc @
// define cashDrawerEjector command
static const struct command cashDrawerEject[2] = {
{5, (char[5]){0x1b, 0x70, 0, 0x40, 0x50}}, // esc p N @ P
{5, (char[5]){0x1b, 0x70, 1, 0x40, 0x50}}};
// define raster mode start command
static const struct command rasterModeStartCommand = {
4, (char[4]){0x1d, 0x76, 0x30, 0}}; // esc v 0
#ifndef DEBUGP
static inline void mputchar(char c) { putchar(c); }
#else
FILE *lfd = 0;
// putchar with debug wrapper
static inline void mputchar(char c) {
unsigned char m = c;
if (lfd)
fprintf(lfd, "%02x ", m);
putchar(m);
}
#endif
// procedure to output an array
static inline void outputarray(const char *array, int length) {
int i = 0;
for (; i < length; ++i)
mputchar(array[i]);
}
// output a command
static inline void outputCommand(struct command output) {
outputarray(output.command, output.length);
}
static inline int lo(int val) { return val & 0xFF; }
static inline int hi(int val) { return lo(val >> 8); }
// enter raster mode and set up x and y dimensions
static inline void rasterheader(int xsize, int ysize) {
outputCommand(rasterModeStartCommand);
mputchar(lo(xsize));
mputchar(hi(xsize));
mputchar(lo(ysize));
mputchar(hi(ysize));
}
// print all unprinted (i.e. flush the buffer)
// then feed given number of lines
static inline void skiplines(int size) {
mputchar(0x1b);
mputchar(0x4a); // esc j
mputchar(size);
}
// get an option
static inline int getOptionChoiceIndex(const char *choiceName,
ppd_file_t *ppd) {
ppd_choice_t *choice;
ppd_option_t *option;
choice = ppdFindMarkedChoice(ppd, choiceName);
if (choice == NULL) {
if ((option = ppdFindOption(ppd, choiceName)) == NULL)
return -1;
if ((choice = ppdFindChoice(option, option->defchoice)) == NULL)
return -1;
}
return atoi(choice->choice);
}
static void initializeSettings(char *commandLineOptionSettings) {
ppd_file_t *ppd = NULL;
cups_option_t *options = NULL;
int numOptions = 0;
ppd = ppdOpenFile(getenv("PPD"));
ppdMarkDefaults(ppd);
numOptions = cupsParseOptions(commandLineOptionSettings, 0, &options);
if ((numOptions != 0) && (options != NULL)) {
cupsMarkOptions(ppd, numOptions, options);
cupsFreeOptions(numOptions, options);
}
memset(&settings, 0x00, sizeof(struct settings_));
settings.cashDrawer1 = getOptionChoiceIndex("CashDrawer1Setting", ppd);
settings.cashDrawer2 = getOptionChoiceIndex("CashDrawer2Setting", ppd);
settings.blankSpace = getOptionChoiceIndex("BlankSpace", ppd);
settings.feedDist = getOptionChoiceIndex("FeedDist", ppd);
ppdClose(ppd);
}
// sent on the beginning of print job
void jobSetup() {
if (settings.cashDrawer1 == 1)
outputCommand(cashDrawerEject[0]);
if (settings.cashDrawer2 == 1)
outputCommand(cashDrawerEject[1]);
outputCommand(printerInitializeCommand);
}
// sent at the very end of print job
void ShutDown() {
if (settings.cashDrawer1 == 2)
outputCommand(cashDrawerEject[0]);
if (settings.cashDrawer2 == 2)
outputCommand(cashDrawerEject[1]);
outputCommand(printerInitializeCommand);
}
// sent at the end of every page
#ifndef __sighandler_t
typedef void (*__sighandler_t)(int);
#endif
__sighandler_t old_signal;
void EndPage() {
int i;
for (i = 0; i < settings.feedDist; ++i)
skiplines(0x18);
signal(15, old_signal);
}
// sent on job canceling
void cancelJob() {
int i = 0;
for (; i < 0x258; ++i)
mputchar(0);
EndPage();
ShutDown();
}
// invoked before starting to print a page
void pageSetup() { old_signal = signal(15, cancelJob); }
//////////////////////////////////////////////
//////////////////////////////////////////////
int main(int argc, char *argv[]) {
int fd = 0; // File descriptor providing CUPS raster data
cups_raster_t *ras = NULL; // Raster stream for printing
cups_page_header2_t header; // CUPS Page header
int page = 0; // Current page
int y = 0; // Vertical position in page 0 <= y <= header.cupsHeight
unsigned char *rasterData = NULL; // Pointer to raster data from CUPS
unsigned char *originalRasterDataPtr =
NULL; // Copy of original pointer for freeing buffer
if (argc < 6 || argc > 7) {
fputs("ERROR: rastertozj job-id user title copies options [file]\n",
stderr);
return EXIT_FAILURE;
}
if (argc == 7) {
if ((fd = open(argv[6], O_RDONLY)) == -1) {
perror("ERROR: Unable to open raster file - ");
sleep(1);
return EXIT_FAILURE;
}
} else
fd = 0;
#ifdef DEBUGP
lfd = fopen(DEBUGFILE, "w");
#endif
initializeSettings(argv[5]);
jobSetup();
ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
page = 0;
while (cupsRasterReadHeader2(ras, &header)) {
if ((header.cupsHeight == 0) || (header.cupsBytesPerLine == 0))
break;
#ifdef DEBUGP
if (lfd)
fprintf(lfd, "\nheader.cupsHeight=%d, header.cupsBytesPerLine=%d\n",
header.cupsHeight, header.cupsBytesPerLine);
#endif
if (rasterData == NULL) {
rasterData = malloc(header.cupsBytesPerLine * 24);
if (rasterData == NULL) {
if (originalRasterDataPtr != NULL)
free(originalRasterDataPtr);
cupsRasterClose(ras);
if (fd != 0)
close(fd);
return EXIT_FAILURE;
}
originalRasterDataPtr = rasterData; // used to later free the memory
}
fprintf(stderr, "PAGE: %d %d\n", ++page, header.NumCopies);
pageSetup();
int foo = (header.cupsWidth > 0x180) ? 0x180 : header.cupsWidth;
foo = (foo + 7) & 0xFFFFFFF8;
int width_size = foo >> 3;
#ifdef DEBUGP
if (lfd)
fprintf(lfd, "\nheader.cupsWidth=%d, foo=%d, width_size=%d\n",
header.cupsWidth, foo, width_size);
#endif
y = 0;
int zeroy = 0;
while (y < header.cupsHeight) {
if ((y & 127) != 0)
fprintf(stderr, "INFO: Printing page %d, %d%% complete...\n", page,
(100 * y / header.cupsHeight));
int rest = header.cupsHeight - y;
if (rest > 24)
rest = 24;
#ifdef DEBUGP
if (lfd)
fprintf(lfd, "\nProcessing block of %d, starting from %d lines\n", rest,
y);
#endif
y += rest;
if (y) {
unsigned char *buf = rasterData;
int j;
for (j = 0; j < rest; ++j) {
if (!cupsRasterReadPixels(ras, buf, header.cupsBytesPerLine))
break;
buf += width_size;
}
#ifdef DEBUGP
if (lfd)
fprintf(lfd, "\nRead %d lines\n", j);
#endif
if (j < rest)
continue;
}
int rest_bytes = rest * width_size;
int j;
for (j = 0; j < rest_bytes; ++j)
if (rasterData[j] != 0)
break;
#ifdef DEBUGP
if (lfd)
fprintf(lfd, "\nChecked %d bytes of %d for zero\n", j, rest_bytes);
#endif
if (j >= rest_bytes) {
++zeroy;
continue;
}
for (; zeroy > 0; --zeroy)
skiplines(24);
rasterheader(width_size, rest);
outputarray((char *)rasterData, width_size * 24);
skiplines(0);
}
if (!settings.blankSpace)
for (; zeroy > 0; --zeroy)
skiplines(24);
EndPage();
}
ShutDown();
if (originalRasterDataPtr)
free(originalRasterDataPtr);
cupsRasterClose(ras);
if (fd)
close(fd);
fputs(page ? "INFO: Ready to print.\n" : "ERROR: No pages found!\n", stderr);
#ifdef DEBUGP
if (lfd)
fclose(lfd);
#endif
return page ? EXIT_SUCCESS : EXIT_FAILURE;
}
// end of rastertozj.c