summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLuca Niccoli <lultimouomo@gmail.com>2013-08-12 18:40:39 +0200
committerLuca Niccoli <lultimouomo@gmail.com>2013-08-12 18:40:39 +0200
commitf5f67647244b856e46e81c4b393e01bd47a1f2cc (patch)
treed24993a220115186d9d5b72f73257ce9fee62233 /src
Imported Upstream version 1.0.1
Diffstat (limited to 'src')
-rw-r--r--src/Makefile35
-rw-r--r--src/band.cpp135
-rw-r--r--src/bandanalyser.cpp94
-rw-r--r--src/compress.cpp189
-rw-r--r--src/pbmimage.cpp253
-rw-r--r--src/pbmtospl2.cpp204
-rw-r--r--src/printer.cpp351
-rw-r--r--src/raster.cpp153
-rwxr-xr-xsrc/rastertospl2bin0 -> 101100 bytes
-rw-r--r--src/rastertospl2.cpp90
-rw-r--r--src/spl2.cpp462
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(&timestamp);
+ timeinfo = localtime(&timestamp);
+ 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
new file mode 100755
index 0000000..52df29b
--- /dev/null
+++ b/src/rastertospl2
Binary files differ
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: */