diff options
author | Luca Niccoli <lultimouomo@gmail.com> | 2013-08-12 18:40:39 +0200 |
---|---|---|
committer | Luca Niccoli <lultimouomo@gmail.com> | 2013-08-12 18:40:39 +0200 |
commit | f5f67647244b856e46e81c4b393e01bd47a1f2cc (patch) | |
tree | d24993a220115186d9d5b72f73257ce9fee62233 /src |
Imported Upstream version 1.0.1
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 35 | ||||
-rw-r--r-- | src/band.cpp | 135 | ||||
-rw-r--r-- | src/bandanalyser.cpp | 94 | ||||
-rw-r--r-- | src/compress.cpp | 189 | ||||
-rw-r--r-- | src/pbmimage.cpp | 253 | ||||
-rw-r--r-- | src/pbmtospl2.cpp | 204 | ||||
-rw-r--r-- | src/printer.cpp | 351 | ||||
-rw-r--r-- | src/raster.cpp | 153 | ||||
-rwxr-xr-x | src/rastertospl2 | bin | 0 -> 101100 bytes | |||
-rw-r--r-- | src/rastertospl2.cpp | 90 | ||||
-rw-r--r-- | src/spl2.cpp | 462 |
11 files changed, 1966 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..00de810 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,35 @@ +# +# Makefile (C) 2006, Aurélien Croc (AP²C) +# +# This project has been placed under the GPL Licence. +# + +CXXFLAGS += -I../include -Wall -g -O0 +LDFLAGS += -lcups -lcupsimage + +OBJECTS := spl2.o printer.o band.o compress.o bandanalyser.o +HEADERS := include/spl2.h include/document.h include/printer.h \ + include/error.h include/band.h include/raster.h \ + include/bandanalyser.h + + +all: rastertospl2 +rastertospl2: $(OBJECTS) rastertospl2.o raster.o + $(CXX) $(LDFLAGS) -o $@ $^ + +pbmtospl2: $(OBJECTS) pbmtospl2.o pbmimage.o + $(CXX) $(LDFLAGS) -o $@ $^ + +%.o: %.cpp $(HEADERS) + $(CXX) $(CXXFLAGS) -c $< + +install: rastertospl2 + install -m 755 -s rastertospl2 ${CUPSFILTER} + +.PHONY: clean distclean +clean: + $(RM) *.o + +distclean: clean + $(RM) rastertospl2 pbmtospl2 + diff --git a/src/band.cpp b/src/band.cpp new file mode 100644 index 0000000..48c7a16 --- /dev/null +++ b/src/band.cpp @@ -0,0 +1,135 @@ +/* + * band.cpp (C) 2006, Aurélien Croc (AP²C) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id: band.cpp 49 2006-11-29 10:57:15Z ap2c $ + * + */ +#include "band.h" +#include "error.h" +#include "compress.h" +#include <stdlib.h> +#include <string.h> + + +/* + * Méthodes internes + * Internal methods + */ +unsigned char *Band::_algorithm0(size_t *size) +{ + unsigned char *tmp; + + *size = _width * _height; + tmp = new unsigned char[*size]; + memcpy(tmp, _band, _height * _width); + return tmp; +} + +unsigned char *Band::_algorithm11(size_t *size) +{ + struct BandArray band; + unsigned char *output; + + output = new unsigned char[_width * _height + 8]; + band.array = output; + band.next = output + 8; + band.prev = output; + *(uint32_t *)output = 0x09ABCDEF; + + calcOccurs(_band, _height, _width, 0x11); + compressBand(&band, _band, _width, _height); + *size = band.next - band.array; + return band.array; +} + +/*int Band::initCompression() +{ +}*/ + + + +/* + * Constructeur - Destructeur + * Init - Uninit + */ +Band::Band(unsigned long bandWidth, unsigned long bandHeight) +{ + _line = 0; + _width = (bandWidth + 7) >> 3; + _height = bandHeight; + _band = NULL; +} + +Band::~Band() +{ + if (_band) + delete[] _band; +} + + + +/* + * Ajout d'une ligne + * Add a line + */ +int Band::addLine(unsigned char *line, unsigned long width) +{ + int off = _line; + + if (!_line) + _empty = false; + if (!_band) { + _band = new unsigned char[_width * _height]; + memset(_band, 0xFF, _width * _height); + } + + // Clip the text + line += _clipping; + width -= _clipping; + + if (_line == _height) { + ERROR(_("Band::addLine: the end of the band has been " + "reached")); + return -1; + } + + for (unsigned int i=0; i < width; i++) { + _band[off] = ~line[i]; + off += _height; + } + + _line++; + return 0; +} + + + +/* + * Exportation d'une bande + * Export a band + */ + +unsigned char* Band::exportBand(int algorithm, size_t *size) +{ + if (algorithm == 0) + return _algorithm0(size); + else if (algorithm == 0x11) + return _algorithm11(size); + else + return NULL; +} + diff --git a/src/bandanalyser.cpp b/src/bandanalyser.cpp new file mode 100644 index 0000000..df61a51 --- /dev/null +++ b/src/bandanalyser.cpp @@ -0,0 +1,94 @@ +/* + * bandanalyser.cpp (C) 2006, Aurélien Croc (AP²C) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id: bandanalyser.cpp 60 2006-12-14 01:03:17Z ap2c $ + * + */ +#include "bandanalyser.h" +#include "band.h" +#include "error.h" + + +/* + * Vérification si les bandes sont vides + * Check if bands are empty + */ +void checkEmptyBand(Band *band) +{ + const unsigned char *data; + size_t i, size, last; + unsigned char c; + + data = band->band(); + size = (band->width() * band->height() + 7) >> 3; + last = size % sizeof(unsigned long); + size -= last; + + for (i=0; i < size; i += sizeof(unsigned long)) + if (~*((unsigned long *)&data[i]) != 0) { + return; + } + for (; i < last + size; i++) { + c = ~data[i]; + if (c != 0) + return; + } + band->setEmpty(); +} + +void correctBlackColor(Band *bandC, Band *bandM, Band *bandY, Band *bandB) +{ + unsigned char *cyan, *magenta, *yellow, *black; + unsigned long i; + size_t size, last; + + cyan = bandC->band(); + magenta = bandM->band(); + yellow = bandY->band(); + black = bandB->band(); + + size = (bandC->width() * bandC->height() + 7) >> 3; + last = size % sizeof(unsigned long); + size -= last; + + for (i=0; i < size; i += sizeof(unsigned long)) { + unsigned long mask; + + mask = *((unsigned long *)&cyan[i]) | + *((unsigned long *)&magenta[i]) | + *((unsigned long *)&yellow[i]); + if (~mask == 0) + continue; + + *((unsigned long *)&cyan[i]) |= ~mask; + *((unsigned long *)&magenta[i]) |= ~mask; + *((unsigned long *)&yellow[i]) |= ~mask; + *((unsigned long *)&black[i]) &= mask; + } + + for (; i < last + size; i++) { + unsigned char mask; + + mask = cyan[i] | magenta[i] | yellow[i]; + if (mask == 0xFF) + continue; + cyan[i] |= ~mask; + magenta[i] |= ~mask; + yellow[i] |= ~mask; + black[i] &= mask; + } +} diff --git a/src/compress.cpp b/src/compress.cpp new file mode 100644 index 0000000..4516e09 --- /dev/null +++ b/src/compress.cpp @@ -0,0 +1,189 @@ +/* + * compress.cpp (C) 2006, Aurélien Croc (AP²C) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id: compress.cpp 60 2006-12-14 01:03:17Z ap2c $ + * + */ +#include "compress.h" +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + + +static int32_t ptrArray[0x40]; +static uint32_t maxSizeArray[0x40]; + +#define COMPRESS_SAMPLE_RATE 0x800 + + +static int _compare(const void *n1, const void *n2) +{ + // n2 and n1 has been exchanged since the first + // element of the array MUST be the biggest + return *(uint32_t *)n2 - *(uint32_t *)n1; +} + +int calcOccurs(unsigned char *band, unsigned long bandHeight, + unsigned long bandWidth, unsigned long number) +{ + uint32_t occurs[COMPRESS_SAMPLE_RATE * 2]; + size_t i, j, size; + + size = bandWidth * bandHeight; + + // Initialize buffers + for (i=0; i < COMPRESS_SAMPLE_RATE; i++) { + occurs[i*2] = 0; + occurs[i*2 + 1] = i; + } + + // Calculate the byte occurrence + for (i=COMPRESS_SAMPLE_RATE; i < size; i += COMPRESS_SAMPLE_RATE) { + char b = band[i]; + + for (j=1; j < COMPRESS_SAMPLE_RATE; j++) + if (band[i - j] == b) + occurs[(j-1)*2]++; + } + + // Order the array + qsort(occurs, COMPRESS_SAMPLE_RATE, sizeof(uint32_t)*2, _compare); + + // Get the first 0x40 elements + for (i=0; i < 0x40; i++) + ptrArray[i] = ~occurs[i*2 + 1] - 1; + + // Get the maximum length of a compressed data + if (number > 0x63 || !number) { + for (i=0; i < 0x40; i++) + maxSizeArray[i] = 0x202; + } else { + uint32_t l; + + l = 0x6464 / (number << 6); + for (i=0; i < 0x40; i++) { + uint32_t v = 0x202 - l * i; + + if (v < 3) + v = 3; + maxSizeArray[i] = v; + } + } + + return 0; +} + +int compressBand(struct BandArray *bandArray, unsigned char *beginIn, + unsigned long bandWidth, unsigned long bandHeight) +{ + unsigned char *out, *endOut, *in, *endIn, *rawDataPtr = 0; + size_t max, repCnt, maxRepCnt, rawDataNr = 0; + int32_t lastPtr = 0, si; + size_t i, maxPtr; + + // Initialize some variables + out = bandArray->next; + endOut = bandArray->next + bandWidth * bandHeight; + in = beginIn; + endIn = beginIn + bandWidth * bandHeight; + + // Print the table + for (i=0; i < 0x40; i++) { + *(int16_t *)out = ~(int16_t)ptrArray[i]; + out += 2; + if (ptrArray[i] < lastPtr) + lastPtr = ptrArray[i]; + } + + // Print the first uncompressed bytes + lastPtr = ~lastPtr; + if (lastPtr > 0x80) + lastPtr = 0x80; + *(uint32_t *)(bandArray->prev + 4) = lastPtr; + for (si=0; si < lastPtr; si++) { + *out = *in; + out++; + in++; + } + + // Compress the data + do { + max = endIn - in > 0x202 ? 0x202 : endIn - in; + + if (!max) { + if (rawDataNr) + *rawDataPtr = rawDataNr - 1; + bandArray->next = out; + return 0; + } else if (max >= 2) { + maxRepCnt = 0; + maxPtr = 0; + + // Check the best similar piece of data + for (i=0; i < 0x40; i++) { + unsigned char *seq = in + ptrArray[i] + 1; + + if (seq < beginIn) + continue; + if (in <= seq) + continue; + for (repCnt = 0; repCnt < max && repCnt < maxSizeArray[i]; + repCnt++) + if (in[repCnt] != seq[repCnt]) + break; + if (repCnt > maxRepCnt) { + maxRepCnt = repCnt; + maxPtr = i; + } + } + + // If the piece is large enough, use it! + if (maxRepCnt > 2) { + maxRepCnt -= 3; + out[0] = 0x80 | maxRepCnt & 0x7F; + out[1] = ((maxRepCnt >> 1) & 0xC0) | maxPtr & 0x3F; + out += 2; + in += maxRepCnt + 3; + if (rawDataNr) { + *rawDataPtr = rawDataNr - 1; + rawDataNr = 0; + } + continue; + } + } + + // Write the uncompressed data + rawDataNr++; + if (rawDataNr == 1) { + rawDataPtr = out; + out++; + } else if (rawDataNr == 0x80) { + *rawDataPtr = 0x7F; + rawDataNr = 0; + } + *out = *in; + out++; + in++; + + } while (out <= endOut); + + return -1; +} + +/* vim: set expandtab tabstop=4 shiftwidth=4 smarttab tw=80 cin: */ + diff --git a/src/pbmimage.cpp b/src/pbmimage.cpp new file mode 100644 index 0000000..eff2be3 --- /dev/null +++ b/src/pbmimage.cpp @@ -0,0 +1,253 @@ +/* + * pbmimage.cpp (C) 2006, Aurélien Croc (AP²C) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id: pbmimage.cpp 56 2006-12-13 15:20:59Z ap2c $ + * + */ +#include "pbmimage.h" +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include "error.h" + +/* + * Constructeur - Destructeur + * Init - Uninit + */ +PbmImage::PbmImage(const char *black, const char *cyan, const char *magenta, + const char *yellow) +{ + _color = !cyan && !magenta && !yellow ? false : true; + _blackFile = black; + _cyanFile = cyan; + _magentaFile = magenta; + _yellowFile = yellow; + _black = NULL; + _cyan = NULL; + _magenta = NULL; + _yellow = NULL; + + _width = 0; + _height = 0; + _lineSize = 0; + _line = 0; + _lineBuffer = NULL; + _currentColor = 1; + +} + +PbmImage::~PbmImage() +{ + unload(); +} + + + +/* + * Chargement de l'image + * Load the image + */ +void PbmImage::unload() +{ + if (_black) { + fclose(_black); + _blackFile = NULL; + _black = NULL; + } + if (_color) { + if (_cyan) { + fclose(_cyan); + _cyanFile = NULL; + _cyan = NULL; + } + if (_magenta) { + fclose(_magenta); + _magentaFile = NULL; + _magenta = NULL; + } + if (_yellow) { + fclose(_yellow); + _yellowFile = NULL; + _yellow = NULL; + } + } + if (_lineBuffer) { + delete[] _lineBuffer; + _lineBuffer= NULL; + } +} + +int PbmImage::load() +{ + uint32_t width, height; + char buffer[1024]; + + // Open the different files + if (!(_black = fopen(_blackFile, "r"))) { + fprintf(stderr, _("Cannot open black file %s\n"), _blackFile); + return -1; + } + if (_color) { + if (_cyanFile && !(_cyan = fopen(_cyanFile, "r"))) { + fprintf(stderr, _("Cannot open cyan file %s\n"), + _cyanFile); + return -1; + } + if (_magentaFile && !(_magenta = fopen(_magentaFile, "r"))) { + fprintf(stderr, _("Cannot open magenta file %s\n"), + _magentaFile); + return -1; + } + if (_yellowFile && !(_yellow = fopen(_yellowFile, "r"))) { + fprintf(stderr, _("Cannot open yellow file %s\n"), + _yellowFile); + return -1; + } + } + + // Read the PBM header + fgets((char *)&buffer, sizeof(buffer), _black); + if (strcmp((char *)&buffer, "P4\n")) { + fprintf(stderr, _("Invalid PBM file for file %s\n"), + _blackFile); + return -1; + } + fgets((char *)&buffer, sizeof(buffer), _black); + fscanf(_black, "%u %u\n", &width, &height); + _width = width; + _height = height; + _lineSize = (width + 7) >> 3; + + if (_color) { + unsigned int tmpW, tmpH; + + if (_cyan) { + fgets((char *)&buffer, sizeof(buffer), _cyan); + if (strcmp((char *)&buffer, "P4\n")) { + fprintf(stderr, _("Invalid PBM file for file " + "%s\n"), _cyanFile); + return -1; + } + fgets((char *)&buffer, sizeof(buffer), _cyan); + fscanf(_cyan, "%u %u\n", &tmpW, &tmpH); + if ((tmpW != width) || (tmpH != height)) { + fprintf(stderr, _("The different PBM layers " + "must have the same size\n")); + return -1; + } + } + if (_magenta) { + fgets((char *)&buffer, sizeof(buffer), _magenta); + if (strcmp((char *)&buffer, "P4\n")) { + fprintf(stderr, _("Invalid PBM file for file " + "%s\n"), _magentaFile); + return -1; + } + fgets((char *)&buffer, sizeof(buffer), _magenta); + fscanf(_magenta, "%u %u\n", &tmpW, &tmpH); + if ((tmpW != width) || (tmpH != height)) { + fprintf(stderr, _("The different PBM layers " + "must have the same size\n")); + return -1; + } + } + if (_yellow) { + fgets((char *)&buffer, sizeof(buffer), _yellow); + if (strcmp((char *)&buffer, "P4\n")) { + fprintf(stderr, _("Invalid PBM file for file " + "%s\n"), _yellowFile); + return -1; + } + fgets((char *)&buffer, sizeof(buffer), _yellow); + fscanf(_yellow, "%u %u\n", &tmpW, &tmpH); + if ((tmpW != width) || (tmpH != height)) { + fprintf(stderr, _("The different PBM layers " + "must have the same size\n")); + return -1; + } + } + } + + return 0; +} + +int PbmImage::loadPage(Printer *printer) +{ + printer->setCompVersion(0x11); + if (_line) + return 1; + + return 0; +} + + + +/* + * Lecture d'une ligne + * Read a line + */ +int PbmImage::readLine() +{ + if (!_lineBuffer) + _lineBuffer = new unsigned char[_lineSize]; + + if (_line >= _height) { + memset(_lineBuffer, 0x00, _lineSize); + return _lineSize; + } + + if (_color) { + switch(_currentColor) { + case 1: + if (_cyan) + fread(_lineBuffer, 1, _lineSize, _cyan); + else + memset(_lineBuffer, 0x00, _lineSize); + _currentColor++; + break; + case 2: + if (_magenta) + fread(_lineBuffer, 1, _lineSize, + _magenta); + else + memset(_lineBuffer, 0x00, _lineSize); + _currentColor++; + break; + case 3: + if (_yellow) + fread(_lineBuffer, 1, _lineSize, + _yellow); + else + memset(_lineBuffer, 0x00, _lineSize); + _currentColor++; + break; + case 4: + fread(_lineBuffer, 1, _lineSize, _black); + _currentColor = 1; + _line++; + break; + } + } else { + fread(_lineBuffer, 1, _lineSize, _black); + _line++; + } + return _lineSize; +} + diff --git a/src/pbmtospl2.cpp b/src/pbmtospl2.cpp new file mode 100644 index 0000000..befec7e --- /dev/null +++ b/src/pbmtospl2.cpp @@ -0,0 +1,204 @@ +/* + * pbmtospl2.cpp (C) 2006, Aurélien Croc (AP²C) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id: pbmtospl2.cpp 57 2006-12-13 15:40:54Z ap2c $ + * + */ + +#include "pbmimage.h" +#include "printer.h" +#include "spl2.h" +#include "error.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <cups/ppd.h> +#include <cups/cups.h> + +static void _printHelp() +{ + printf(_("Usage: %s [options] <black PBM file> [<cyan PBM " + "file>] [<magenta PBM file>] [<yellow PBM file>]\n\n"), + "pbmtospl2"); + printf(_("Available options:\n")); + printf(_(" -h --help Print this help message\n")); + printf(_(" -o --output <file> Change the output file " + "[default to stdout]\n")); + printf(_(" -P --ppd <file> Select the ppd file to use\n")); + printf(_(" -p --papersize <name> Select the paper to use\n")); + printf(_(" -r --resolution <res> Select the resolution\n")); +} + +int main(int argc, const char **argv) +{ + const char *black=NULL, *cyan=NULL, *magenta=NULL, *yellow=NULL; + const char *resolution=NULL, *paperSize=NULL; + const char *output=NULL, *ppdFile=NULL; + PbmImage *document; + Printer *printer; + FILE *ppdHandle; + ppd_file_t* ppd; + int i, j, k; + SPL2 spl2; + + + // Check options + for (i=1; i < argc; i++) { + if (argv[i][0] != '-') + break; + // Long options + if (argv[i][1] == '-') { + if (!strcmp(argv[i], "--help")) { + _printHelp(); + return 0; + } else if (!strcmp(argv[i], "--output")) { + output = argv[i+1]; + i++; + } else if (!strcmp(argv[i], "--ppd")) { + ppdFile = argv[i+1]; + i++; + } else if (!strcmp(argv[i], "--resolution")) { + resolution = argv[i+1]; + i++; + } else if (!strcmp(argv[i], "--papersize")) { + paperSize = argv[i+1]; + i++; + } else { + fprintf(stderr, _("Invalid argument %s\n\n"), + argv[i]); + _printHelp(); + return 1; + } + + // Short options + } else { + k = i+1; + for (j=1; argv[i][j]; j++) { + switch (argv[i][j]) { + case 'h': + _printHelp(); + return 0; + case 'o': + output = argv[k]; + k++; + break; + case 'P': + ppdFile = argv[k]; + k++; + break; + case 'r': + resolution = argv[k]; + k++; + break; + case 'p': + paperSize = argv[k]; + k++; + break; + default: + fprintf(stderr, _("Invalid " + "argument -%c\n\n"), + argv[i][j]); + _printHelp(); + return 1; + }; + } + i = k-1; + } + } + + // Get the layer files + if (!argv[i]) { + fprintf(stderr, _("No black PBM file specified.\n\n")); + _printHelp(); + return 1; + } else { + black = argv[i]; + if (argv[i+1]) { + cyan = argv[i+1]; + if (argv[i+2]) { + magenta = argv[i+2]; + if (argv[i+3]) + yellow = argv[i+3]; + } + } + } + + // Open the PPD file + if (ppdFile) { + if (!(ppdHandle = fopen(ppdFile, "r"))) { + fprintf(stderr, _("Cannot open PPD file %s\n"), + ppdFile); + return errno; + } + ppd = ppdOpen(ppdHandle); + } else { + fprintf(stderr, _("No PPD file specified.\n\n")); + _printHelp(); + return 1; + } + + // Mark the options + ppdMarkDefaults(ppd); + if (resolution) + ppdMarkOption(ppd, "Resolution", resolution); + if (paperSize) + ppdMarkOption(ppd, "PaperSize", paperSize); + + + // Prepare the output + if (output) { + if (!freopen(output, "w", stdout)) { + fprintf(stderr, _("Cannot open output file %s\n"), + output); + return errno; + } + } + setbuf(stdout, NULL); + + + // Create the document + + // Create the document + document = new PbmImage(black, magenta, cyan, yellow); + if (document->load()) { + delete document; + return 1; + } + + // Create the printer + printer = new Printer(ppd); + + // Convert and print + DEBUG("Génération du code...."); + spl2.setPrinter(printer); + spl2.setOutput(stdout); + spl2.beginDocument(); + + while (!spl2.printPage(document, 1)); + + spl2.closeDocument(); + + ppdClose(ppd); + fclose(ppdHandle); + delete document; + delete printer; + + return 0; +} + diff --git a/src/printer.cpp b/src/printer.cpp new file mode 100644 index 0000000..89dd08f --- /dev/null +++ b/src/printer.cpp @@ -0,0 +1,351 @@ +/* + * printer.cpp (C) 2006, Aurélien Croc (AP²C) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id: printer.cpp 68 2006-12-15 07:37:13Z ap2c $ + * + */ +#include "printer.h" +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <time.h> +#include "error.h" + +/* + * Fonctions internes + * Internal functions + */ +long double Printer::_convertX(long double d) const +{ + return d * _xresolution / 72.; +} + +long double Printer::_convertY(long double d) const +{ + return d * _yresolution / 72.; +} + +char *Printer::_convertStr(const char *str) const +{ + unsigned int i; + char *out = new char[strlen(str)]; + + for (i=0; *str; str++) { + if (*str == '<' && strlen(str) >= 3 && isxdigit(*(str+1))) { + char temp[3] = {0, 0, 0}; + + str++; + temp[0] = *str; + str++; + if (*str != '>' && (!isxdigit(*str) || + *(str + 1) != '>')) { + out[i] = '<'; + out[i+1] = temp[0]; + i += 2; + continue; + } + if (*str != '>') { + temp[1] = *str; + str++; + } + out[i] = (char)strtol((char *)&temp, (char **)NULL, 16); + i++; + continue; + } + out[i] = *str; + i++; + } + out[i] = 0; + return out; +} + + + +/* + * Constructeur - Destructeur + * Init - Uninit + */ +Printer::Printer(ppd_file_t *ppd) +{ + ppd_choice_t *choice; + ppd_attr_t *attr; + + + _username = "Unknown"; + _jobname = "No name"; + _ppd = ppd; + _pageSizeX = 595.; + _pageSizeY = 842.; + _marginX = 12.5; + _marginY = 12.5; + _areaX = 582.5; + _areaY = 829.5; + _bandHeight = 0x80; + _duplex = 0x0100; + + // Get the QPDL version and color information + attr = ppdFindAttr(_ppd, "QPDL", "QPDLVersion"); + if (attr) + _qpdlVersion = strtol(attr->value, (char **)NULL, 10); + attr = ppdFindAttr(_ppd, "QPDL", "ColorPrinter"); + _color = attr->value[0] == '1' ? true : false; + + // Get the resolution + if ((choice = ppdFindMarkedChoice(_ppd, "Resolution"))) { + if (!strcmp("300dpi", choice->choice)) { + _xresolution = 300; + _yresolution = 300; + _bandHeight = 0x40; + _qpdlVersion = 0; + } else if (!strcmp("600dpi", choice->choice)) { + _xresolution = 600; + _yresolution = 600; + } else if (!strcmp("1200dpi", choice->choice)) { + _xresolution = 1200; + _yresolution = 1200; + } else if (!strcmp("1200x600pi", choice->choice)) { + _xresolution = 1200; + _yresolution = 600; + } else { + _xresolution = 600; + _yresolution = 600; + } + } else { + _xresolution = 600; + _yresolution = 600; + } + + // Get the paper type + if ((choice = ppdFindMarkedChoice(_ppd, "MediaSize")) || (choice = + ppdFindMarkedChoice(_ppd, "PageSize"))) { + if (!(strcmp(choice->choice, "Letter"))) + _paperType = 0; + else if (!(strcmp(choice->choice, "Legal"))) + _paperType = 1; + else if (!(strcmp(choice->choice, "A4"))) + _paperType = 2; + else if (!(strcmp(choice->choice, "Executive"))) + _paperType = 3; + else if (!(strcmp(choice->choice, "Ledger"))) + _paperType = 4; + else if (!(strcmp(choice->choice, "A3"))) + _paperType = 5; + else if (!(strcmp(choice->choice, "Env10"))) + _paperType = 6; + else if (!(strcmp(choice->choice, "Monarch"))) + _paperType = 7; + else if (!(strcmp(choice->choice, "C5"))) + _paperType = 8; + else if (!(strcmp(choice->choice, "DL"))) + _paperType = 9; + else if (!(strcmp(choice->choice, "B4"))) + _paperType = 10; + else if (!(strcmp(choice->choice, "B5"))) + _paperType = 11; + else if (!(strcmp(choice->choice, "EnvISOB5"))) + _paperType = 12; + else if (!(strcmp(choice->choice, "A5"))) + _paperType = 16; + else if (!(strcmp(choice->choice, "A6"))) + _paperType = 17; + else if (!(strcmp(choice->choice, "EnvISOB6"))) + _paperType = 18; + else if (!(strcmp(choice->choice, "C6"))) + _paperType = 23; + else if (!(strcmp(choice->choice, "Folio"))) + _paperType = 24; + else { + ERROR(_("Printer::Printer: Invalid MediaSize %s"), + choice->choice); + _paperType = 2; + } + } else + _paperType = 2; + + // Get the paper source + if ((choice = ppdFindMarkedChoice(_ppd, "InputSlot"))) { + if (!(strcmp(choice->choice, "Auto"))) + _paperSource = 1; + else if (!(strcmp(choice->choice, "Manual"))) + _paperSource = 2; + else if (!(strcmp(choice->choice, "Multi"))) + _paperSource = 3; + else if (!(strcmp(choice->choice, "Upper"))) + _paperSource = 4; + else if (!(strcmp(choice->choice, "Lower"))) + _paperSource = 5; + else if (!(strcmp(choice->choice, "Envelope"))) + _paperSource = 6; + else if (!(strcmp(choice->choice, "Tray3"))) + _paperSource = 7; + else { + ERROR(_("Printer::Printer: Invalid InputSlot %s"), + choice->choice); + _paperSource = 1; + } + } else + _paperSource = 1; + + // Get the duplex + if ((choice = ppdFindMarkedChoice(_ppd, "Duplex"))) { + if (!(strcmp(choice->choice, "None"))) + _duplex = 0; + else if (!(strcmp(choice->choice, "DuplexNoTumble"))) + _duplex = 0x0101; + else if (!(strcmp(choice->choice, "DuplexTumble"))) + _duplex = 0x0001; + else + _duplex = 0x0100; + } + if ((choice = ppdFindMarkedChoice(_ppd, "JCLDuplex"))) { + if (!(strcmp(choice->choice, "None"))) + _duplex = 0; + else if (!(strcmp(choice->choice, "DuplexNoTumble"))) + _duplex = 0x0101; + else if (!(strcmp(choice->choice, "DuplexTumble"))) + _duplex = 0x0001; + else + _duplex = 0x0100; + } + + // Compression algorithm version + _compVersion = 0x11; + + // Get the doc header values + attr = ppdFindAttr(_ppd, "General", "docHeaderValues"); + if (attr) + _docHeaderValues = _convertStr(attr->value); + else { + _docHeaderValues = new char[3]; + _docHeaderValues[0] = 0; + _docHeaderValues[1] = 0; + _docHeaderValues[2] = 0; + } + +} + +Printer::~Printer() +{ + delete[] _docHeaderValues; +} + + +/* + * Émission PJL + * PJL header and footer + */ +void Printer::newJob(FILE *output) +{ + ppd_choice_t *choice; + struct tm *timeinfo; + ppd_attr_t *attr; + time_t timestamp; + + // Send the PJL Begin + attr = ppdFindAttr(_ppd, "PJL", "BeginPJL"); + if (attr) { + char *tmp; + tmp = _convertStr(attr->value); + fprintf(output, "%s", tmp); + delete[] tmp; + } else + fprintf(output, "%%-12345X"); + + // Job information + time(×tamp); + timeinfo = localtime(×tamp); + fprintf(output, "@PJL DEFAULT SERVICEDATE=%04u%02u%02u\n", + 1900+timeinfo->tm_year, timeinfo->tm_mon+1, timeinfo->tm_mday); + fprintf(output, "@PJL SET USERNAME=\"%s\"\n", _username); + fprintf(output, "@PJL SET JOBNAME=\"%s\"\n", _jobname); + + // Get the paper type + if ((choice = ppdFindMarkedChoice(_ppd, "MediaType"))) { + if (!strcmp(choice->choice, "OFF")) + fprintf(output, "@PJL SET PAPERTYPE = OFF\n"); + else + fprintf(output, "@PJL SET PAPERTYPE = %s\n", + choice->choice); + } + + // Get the toner density + if ((choice = ppdFindMarkedChoice(_ppd, "TonerDensity"))) + fprintf(output, "@PJL SET DENSITY = %s\n", choice->choice); + else + fprintf(output, "@PJL SET DENSITY = 3\n"); + + // Get the economode state + if ((choice = ppdFindMarkedChoice(_ppd, "EconoMode")) && + strcmp(choice->choice, "0")) { + if (!strcmp(choice->choice, "ON")) { + fprintf(output, "@PJL SET ECONOMODE = ON\n"); + } else + fprintf(output, "@PJL SET ECONOMODE = OFF\n"); + } + + // Get the powersave state + if ((choice = ppdFindMarkedChoice(_ppd, "PowerSave")) && + strcmp(choice->choice, "False")) { + fprintf(output, "@PJL SET POWERSAVE = ON\n"); + fprintf(output, "@PJL SET POWERSAVETIME = %s\n", + choice->choice); + } + + // Get the jam recovery state + if ((choice = ppdFindMarkedChoice(_ppd, "JamRecovery")) && + !strcmp(choice->choice, "True")) + fprintf(output, "@PJL SET JAMERECOVERY = ON\n"); + else + fprintf(output, "@PJL SET JAMERECOVERY = OFF\n"); + + // Get the SRT mode + if ((choice = ppdFindMarkedChoice(_ppd, "SRTMode"))) { + fprintf(output, "@PJL SET RET = %s\n", choice->choice); + } else + fprintf(output, "@PJL SET RET = NORMAL\n"); + + // Enable the Duplex mode + if (_duplex == 0) + fprintf(output, "@PJL SET DUPLEX = OFF\n"); + else if (_duplex == 0x0101) + fprintf(output, "@PJL SET DUPLEX = ON\n@PJL SET BINDING = " + "LONGEDGE\n"); + else if (_duplex == 0x0001) + fprintf(output, "@PJL SET DUPLEX = ON\n@PJL SET BINDING = " + "SHORTEDGE\n"); +} + +void Printer::endJob(FILE *output) +{ + ppd_attr_t *attr; + + attr = ppdFindAttr(_ppd, "PJL", "EndPJL"); + if (attr) { + char *tmp; + + tmp = _convertStr(attr->value); + fprintf(output, "%s", tmp); + delete[] tmp; + } else + fprintf(output, "\t%%-12345X"); +} + + +/* + * Calcul des dimensions à la résolution demandée + * Calculate dimensions for the approprioate resolution + */ diff --git a/src/raster.cpp b/src/raster.cpp new file mode 100644 index 0000000..a9e973a --- /dev/null +++ b/src/raster.cpp @@ -0,0 +1,153 @@ +/* + * raster.cpp (C) 2006, Aurélien Croc (AP²C) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id: raster.cpp 43 2006-11-26 03:12:21Z ap2c $ + * + */ +#include "raster.h" +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +//#include <cups/ppd.h> +#include "error.h" + +/* + * Constructeur - Destructeur + * Init - Uninit + */ +Raster::Raster(const char *job, const char *user, const char *title, + const char *copies, const char *options, const char *file) +{ + _jobId = job; + _user = user; + _title = title; + _copies = copies; + _options = options; + _file = file; + + _width = 0; + _height = 0; + _lineSize = 0; + _line = 0; + _page = 0; + _lineBuffer = NULL; +} + +Raster::~Raster() +{ + unload(); +} + + + +/* + * Chargement de l'image + * Load the image + */ +void Raster::unload() +{ + if (_lineBuffer) + delete[] _lineBuffer; + cupsRasterClose(_ras); +} + +int Raster::load() +{ + // Open the raster file if needed + if (_file && (_fd = open(_file, O_RDONLY)) == -1) { + fprintf(stderr, _("ERROR: Unable to open the raster file %s\n"), + _file); + sleep(1); + return -1; + } + + _ras = cupsRasterOpen(_fd, CUPS_RASTER_READ); + return 0; +} + +int Raster::loadPage(Printer *printer) +{ + if (!cupsRasterReadHeader(_ras, &_header)) { + DEBUG("Plus de page"); + return 1; + } + _width = _header.cupsWidth; + _height = _header.cupsHeight; + _totalLines = _height; + _lineSize = _header.cupsBytesPerLine; + _line = 0; + _page++; + + // Configure the printer + printer->setResolution(_header.HWResolution[0],_header.HWResolution[1]); + printer->setPageSizeX(_header.PageSize[0]); + printer->setPageSizeY(_header.PageSize[1]); + printer->setMarginX(_header.ImagingBoundingBox[0]); + printer->setMarginY(_header.ImagingBoundingBox[1]); + printer->setAreaX(_header.PageSize[0] - _header.ImagingBoundingBox[0]); + printer->setAreaY(_header.PageSize[1] - _header.ImagingBoundingBox[1]); + printer->setPrintableX(_header.ImagingBoundingBox[2] - + _header.ImagingBoundingBox[0]); + printer->setPrintableY(_header.ImagingBoundingBox[3] - + _header.ImagingBoundingBox[1]); + + // Get some document informations + _color = _header.cupsColorSpace == CUPS_CSPACE_K ? false : true; + printer->setCompVersion(_header.cupsCompression); + + if (_color) { + _totalLines = _totalLines * 4; + _lineSize = _lineSize >> 2; + } + + return 0; +} + + + +/* + * Lecture d'une ligne + * Read a line + */ +int Raster::readLine() +{ + if (!_ras) + return -1; + if (!_lineBuffer) + _lineBuffer = new unsigned char[_lineSize]; + + /* + * so that we can round up to bandHeight, we return an empty line + * after reading more than _height lines. + * -- Keith White + */ + if (_line >= _totalLines) { + memset(_lineBuffer, 0x00, _lineSize); + return _lineSize; + } + + if (cupsRasterReadPixels(_ras, _lineBuffer, _lineSize) < 1) { + ERROR(_("Raster::readLine: Cannot read image data")); + return -1; + } + _line++; + return _lineSize; +} + diff --git a/src/rastertospl2 b/src/rastertospl2 Binary files differnew file mode 100755 index 0000000..52df29b --- /dev/null +++ b/src/rastertospl2 diff --git a/src/rastertospl2.cpp b/src/rastertospl2.cpp new file mode 100644 index 0000000..8ffb169 --- /dev/null +++ b/src/rastertospl2.cpp @@ -0,0 +1,90 @@ +/* + * rastertospl2.cpp (C) 2006, Aurélien Croc (AP²C) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id: rastertospl2.cpp 60 2006-12-14 01:03:17Z ap2c $ + * + */ + +#include "raster.h" +#include "printer.h" +#include "spl2.h" +#include "error.h" + +#include <stdio.h> +#include <stdlib.h> +#include <cups/ppd.h> +#include <cups/cups.h> + +int main(int argc, char **argv) +{ + cups_option_t *options; + Raster *document; + Printer *printer; + ppd_file_t* ppd; + SPL2 spl2; + int nr; + + setbuf(stderr, NULL); + setbuf(stdout, NULL); + + // Check if enough arguments are available + if (argc < 6 || argc > 7) { + fprintf(stderr, _("ERROR: %s job-id user title copies options " + "[file]\n"), argv[0]); + return 1; + } + + // Create the document + document = new Raster(argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6]); + if (document->load()) { + delete document; + return 1; + } + + // Open the PPD file + ppd = ppdOpenFile(getenv("PPD")); + ppdMarkDefaults(ppd); + + // Take modifications in the PPD with options + nr = cupsParseOptions(argv[5], 0, &options); + cupsMarkOptions(ppd, nr, options); + cupsFreeOptions(nr, options); + + + // Create the printer + printer = new Printer(ppd); + printer->setJobName(argv[1]); + printer->setUsername(argv[2]); + + // Convert and print + DEBUG("Génération du code...."); + spl2.setPrinter(printer); + spl2.setOutput(stdout); + spl2.beginDocument(); + + while (!spl2.printPage(document, strtol(argv[4], (char **)NULL, 10))); + + spl2.closeDocument(); + + ppdClose(ppd); + delete document; + delete printer; + + return 0; +} + diff --git a/src/spl2.cpp b/src/spl2.cpp new file mode 100644 index 0000000..4581ae0 --- /dev/null +++ b/src/spl2.cpp @@ -0,0 +1,462 @@ +/* + * spl2.cpp (C) 2006, Aurélien Croc (AP²C) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id: spl2.cpp 64 2006-12-14 01:37:22Z ap2c $ + * + * --- + * Thanks to Keith White for his modifications, corrections and adds. + * + */ +#include "spl2.h" +#include "printer.h" +#include "document.h" +#include "error.h" +#include "band.h" +#include "bandanalyser.h" +#include <stdint.h> + + +/* + * Constructeur - Destructeur + * Init - Uninit + */ +SPL2::SPL2() +{ + _printer = NULL; + _output = NULL; +} + +SPL2::~SPL2() +{ +} + + + +/* + * Génération de l'en-tête et du pied de page PJL + * Write PJL header and footer + */ +int SPL2::beginDocument() +{ + if (!_output || !_printer) { + ERROR(_("SPL2::beginDocument: called with NULL parameters")); + return -1; + } + + _printer->newJob(_output); + fprintf(_output, "@PJL ENTER LANGUAGE = QPDL\n"); + DEBUG("Envoie de l'en-tête du document JPL"); + return 0; +} + +int SPL2::closeDocument() +{ + if (!_output || !_printer) { + ERROR(_("SPL2::closeDocument: called with NULL parameters")); + return -1; + } + _printer->endJob(_output); + DEBUG("Envoie du pied de page du document JPL"); + return 0; +} + + + +/* + * Impression d'une page + * Impress a page + */ +int SPL2::_writeColorBand(Band *band, int color) +{ + unsigned char *data, header[5]; + uint32_t checksum = 0; + size_t size; + + // Compress + if (!(data = band->exportBand(_printer->compVersion(), &size))) + return 1; + + // Calculate the checksum + if (_printer->qpdlVersion() != 0) { + for (unsigned int j = 0; j < size; j++) + checksum += data[j]; + } + + // Write the color header + if (color) { + header[0x0] = color; + fwrite((char *)&header, 1, 1, _output); + } + header[0x0] = _printer->compVersion(); // Compression + if (_printer->qpdlVersion() == 0) { + header[0x1] = size >> 24; // data length + header[0x2] = size >> 16; // data length + header[0x3] = size >> 8; // data length + header[0x4] = size; // data length + } else { + header[0x1] = (size + 4) >> 24; // data length + header[0x2] = (size + 4) >> 16; // data length + header[0x3] = (size + 4) >> 8; // data length + header[0x4] = (size + 4); // data length + } + fwrite((char *)&header, 1, 0x5, _output); + + // Write the data + fwrite(data, 1, size, _output); + delete[]data; + + // Write the checksum + if (_printer->qpdlVersion() != 0) { + header[0x0] = checksum >> 24; + header[0x1] = checksum >> 16; + header[0x2] = checksum >> 8; + header[0x3] = checksum; + fwrite((char *)&header, 1, 0x4, _output); + } + + return 0; +} + +int SPL2::printPage(Document *document, unsigned long nrCopies) +{ + unsigned long width, height, clippingX, clippingY; + unsigned long bandNumber; + unsigned long i; + char header[0x11]; + char errors = 0; + Band *bandC, *bandM, *bandY, *bandB; + + if (!document) { + ERROR(_("SPL2::printPage: called with NULL parameter")); + return -2; + } + // Load a new page + if (document->loadPage(_printer)) + return -1; + if (!document->height()) + return -1; + + + // Send page header FIXME + header[0x0] = 0; // Signature + header[0x1] = _printer->resolutionY() / 100; // Y Resolution + header[0x2] = nrCopies >> 8; // Number of copies 8-15 + header[0x3] = nrCopies; // Number of copies 0-7 + header[0x4] = _printer->paperType(); // Paper type + header[0x5] = document->width() >> 8; // Printable area width + header[0x6] = document->width(); // Printable area width + header[0x7] = document->height() >> 8; // Printable area height + header[0x8] = document->height(); // Printable area height + header[0x9] = _printer->paperSource(); // Paper source + header[0xa] = _printer->docHeaderValues(0); // ??? XXX + header[0xb] = _printer->duplex() >> 8; // Duplex + header[0xc] = _printer->duplex(); // Duplex + header[0xd] = _printer->docHeaderValues(1); // ??? XXX + header[0xe] = _printer->qpdlVersion(); // QPDL Version + header[0xf] = _printer->docHeaderValues(2); // ??? XXX + if (_printer->resolutionY() != _printer->resolutionX()) + header[0x10] = _printer->resolutionX() / 100; // X Resolution + else + header[0x10] = 0; // X Resolution = Y Res. + fwrite((char *)&header, 1, sizeof(header), _output); + + + + // Get the width, height, clipping X and clipping Y values + if (document->width() <= _printer->areaX()) { + clippingX = 0; + width = document->width(); + } else if (document->width() < _printer->pageSizeX()) { + clippingX = (unsigned long)(document->width() - _printer->areaX()); + width = document->width(); + } else { + clippingX = (unsigned long)_printer->marginX(); + width = (unsigned long)_printer->pageSizeX(); + } + if (document->height() <= _printer->areaY()) { + clippingY = 0; + height = document->height(); + } else if (document->height() < _printer->pageSizeY()) { + clippingY = (unsigned long)(document->height() - _printer->areaY()); + height = document->height(); + } else { + clippingY = (unsigned long)_printer->marginY(); + height = (unsigned long)_printer->pageSizeY(); + } + + + // Create the band instance + bandB = new Band((unsigned long)_printer->pageSizeX(), + (unsigned long)_printer->bandHeight()); + if (document->isColor()) { + bandC = new Band((unsigned long)_printer->pageSizeX(), + (unsigned long)_printer->bandHeight()); + bandM = new Band((unsigned long)_printer->pageSizeX(), + (unsigned long)_printer->bandHeight()); + bandY = new Band((unsigned long)_printer->pageSizeX(), + (unsigned long)_printer->bandHeight()); + } + bandNumber = 0; + bandB->setClipping(clippingX); + if (document->isColor()) { + bandC->setClipping(clippingX); + bandM->setClipping(clippingX); + bandY->setClipping(clippingX); + } + + // Clip vertically the document + if (!document->isColor()) + clippingY = clippingY * 4; + for (; clippingY; clippingY--) + document->readLine(); + + // Round up height to a multiple of bandHeight + height += _printer->bandHeight() - (height % _printer->bandHeight()); + + + + + /* + * Read and create each band + */ + for (i = 0; i < height; i++) { + unsigned long res; + + if (document->isColor()) { + res = document->readLine(); + if (res < 0) { + errors = 1; + break; + } else if (!res) + break; + if (bandC->addLine(document->lineBuffer(), (res > width ? width : + res))) { + errors = 1; + break; + } + res = document->readLine(); + if (res < 0) { + errors = 1; + break; + } else if (!res) + break; + if (bandM->addLine(document->lineBuffer(), (res > width ? width : + res))) { + errors = 1; + break; + } + res = document->readLine(); + if (res < 0) { + errors = 1; + break; + } else if (!res) + break; + if (bandY->addLine(document->lineBuffer(), (res > width ? width : + res))) { + errors = 1; + break; + } + } + res = document->readLine(); + if (res < 0) { + errors = 1; + break; + } else if (!res) + break; + if (bandB->addLine(document->lineBuffer(), (res > width ? width : + res))) { + errors = 1; + break; + } + // Compress and send the band if it's complete + if (bandB->isFull()) { + if (document->isColor()) + correctBlackColor(bandC, bandM, bandY, bandB); + checkEmptyBand(bandB); + if (document->isColor()) { + checkEmptyBand(bandC); + checkEmptyBand(bandM); + checkEmptyBand(bandY); + } + if ((!document->isColor() && bandB->isEmpty()) || + (document->isColor() && bandB->isEmpty() && + bandC->isEmpty() && bandM->isEmpty() && bandY->isEmpty())) { + bandNumber++; + bandB->clean(); + if (document->isColor()) { + bandC->clean(); + bandM->clean(); + bandY->clean(); + } + continue; + } + // QPDL Version 0 or 1 + if (_printer->qpdlVersion() < 2) { + // Write the band header + header[0x0] = 0xC; // Signature + header[0x1] = bandNumber; // Band number + header[0x2] = bandB->width() >> 8; // Band width + header[0x3] = bandB->width(); // Band width + header[0x4] = bandB->height() >> 8; // Band height + header[0x5] = bandB->height(); // Band height + fwrite((char *)&header, 1, 0x6, _output); + + if (_printer->isColorPrinter()) { + if (document->isColor()) { + if (!bandC->isEmpty()) { + if (_writeColorBand(bandC, 1)) { + errors = 1; + break; + } + } + if (!bandM->isEmpty()) { + if (_writeColorBand(bandM, 2)) { + errors = 1; + break; + } + } + if (!bandY->isEmpty()) { + if (_writeColorBand(bandY, 3)) { + errors = 1; + break; + } + } + } + if (!bandB->isEmpty()) { + if (_writeColorBand(bandB, 4)) { + errors = 1; + break; + } + } + header[0x0] = 0; // End color + fwrite((char *)&header, 1, 1, _output); + } else { + if (_writeColorBand(bandB, 0)) { + errors = 1; + break; + } + } + + // QPDL Version 2 + } else if (_printer->qpdlVersion() == 2) { + if (_printer->isColorPrinter()) { + if (!bandB->isEmpty()) { + // Write the band header + header[0x0] = 0xC; // Signature + header[0x1] = bandNumber; // Band number + header[0x2] = bandB->width() >> 8; // Band width + header[0x3] = bandB->width(); // Band width + header[0x4] = bandB->height() >> 8; // Band height + header[0x5] = bandB->height(); // Band height + fwrite((char *)&header, 1, 0x6, _output); + if (_writeColorBand(bandB, 4)) { + errors = 1; + break; + } + } + if (document->isColor()) { + if (!bandC->isEmpty()) { + // Write the band header + header[0x0] = 0xC; // Signature + header[0x1] = bandNumber; // Band number + header[0x2] = bandC->width() >> 8; // Band width + header[0x3] = bandC->width(); // Band width + header[0x4] = bandC->height() >> 8; // Band height + header[0x5] = bandC->height(); // Band height + fwrite((char *)&header, 1, 0x6, _output); + if (_writeColorBand(bandC, 1)) { + errors = 1; + break; + } + } + if (!bandM->isEmpty()) { + // Write the band header + header[0x0] = 0xC; // Signature + header[0x1] = bandNumber; // Band number + header[0x2] = bandM->width() >> 8; // Band width + header[0x3] = bandM->width(); // Band width + header[0x4] = bandM->height() >> 8; // Band height + header[0x5] = bandM->height(); // Band height + fwrite((char *)&header, 1, 0x6, _output); + if (_writeColorBand(bandM, 2)) { + errors = 1; + break; + } + } + if (!bandY->isEmpty()) { + // Write the band header + header[0x0] = 0xC; // Signature + header[0x1] = bandNumber; // Band number + header[0x2] = bandY->width() >> 8; // Band width + header[0x3] = bandY->width(); // Band width + header[0x4] = bandY->height() >> 8; // Band height + header[0x5] = bandY->height(); // Band height + fwrite((char *)&header, 1, 0x6, _output); + if (_writeColorBand(bandY, 3)) { + errors = 1; + break; + } + } + } + } else { + // Write the band header + header[0x0] = 0xC; // Signature + header[0x1] = bandNumber; // Band number + header[0x2] = bandB->width() >> 8; // Band width + header[0x3] = bandB->width(); // Band width + header[0x4] = bandB->height() >> 8; // Band height + header[0x5] = bandB->height(); // Band height + fwrite((char *)&header, 1, 0x6, _output); + if (_writeColorBand(bandB, 0)) { + errors = 1; + break; + } + } + } + bandNumber++; + bandB->clean(); + if (document->isColor()) { + bandC->clean(); + bandM->clean(); + bandY->clean(); + } + } + } + + + + // Clean everything + delete bandB; + + if (document->isColor()) { + bandC->clean(); + bandM->clean(); + bandY->clean(); + } + if (errors) + return -11; + + // Write the end of the page + header[0x0] = 1; // Signature + header[0x1] = nrCopies >> 8; // Number of copies 8-15 + header[0x2] = nrCopies; // Number of copies 0-7 + fwrite((char *)&header, 1, 3, _output); + + return 0; +} + +/* vim: set expandtab tabstop=4 shiftwidth=4 smarttab tw=80 cin: */ |