1
/*****************************************************************************\
2
hpcups.cpp : HP cups filter
4
Copyright (c) 2009, Hewlett-Packard Co.
7
Redistribution and use in source and binary forms, with or without
8
modification, are permitted provided that the following conditions
10
1. Redistributions of source code must retain the above copyright
11
notice, this list of conditions and the following disclaimer.
12
2. Redistributions in binary form must reproduce the above copyright
13
notice, this list of conditions and the following disclaimer in the
14
documentation and/or other materials provided with the distribution.
15
3. Neither the name of the Hewlett-Packard nor the names of its
16
contributors may be used to endorse or promote products derived
17
from this software without specific prior written permission.
19
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24
NOT LIMITED TO, PATENT INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR
25
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
28
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
POSSIBILITY OF SUCH DAMAGE.
30
\*****************************************************************************/
42
#include "ijs_server.h"
56
#include <cups/cups.h>
57
#include <cups/raster.h>
60
void SendDbusMessage (const char *dev, const char *printer, int code,
61
const char *username, const int jobid, const char *title);
64
extern int hpijsFaxServer (int argc, char **argv);
94
void HPCups::setLogLevel ()
99
fp = fopen ("/etc/cups/cupsd.conf", "r");
104
if (!fgets (str, 256, fp))
108
if ((p = strstr (str, "hpLogLevel")))
110
p += strlen ("hpLogLevel") + 1;
111
m_iLogLevel = atoi (p);
118
int HPCups::initPrintJob ()
120
// MediaSize msMedia = sizeUSLetter;
122
if (m_iLogLevel & ADDITIONAL_LOG)
127
if (m_cupsHeader.ImagingBoundingBox[0] == 0)
129
m_pSys->FullBleed = 1;
132
m_pSys->ph.width = m_cupsHeader.cupsWidth;
133
m_pSys->ph.height = m_cupsHeader.cupsHeight;
137
* cupsRowStep represents colormode
138
* cupsRowCount represents pen type
139
* cupsOutputType represents quality mode
142
m_pSys->pPC->SetPenSet ((PEN_TYPE) (m_cupsHeader.cupsRowCount - 1));
143
switch (m_cupsHeader.cupsRowStep)
149
colormode = GREY_CMY;
154
m_pSys->pPC->SelectPrintMode ((QUALITY_MODE) m_cupsHeader.cupsCompression,
155
(MEDIATYPE) m_cupsHeader.cupsMediaType,
157
m_pSys->pPC->SetMediaSource ((MediaSource) m_cupsHeader.MediaPosition);
158
if (m_cupsHeader.Duplex)
160
if (m_cupsHeader.Tumble)
161
m_pSys->pPC->SelectDuplexPrinting (DUPLEXMODE_TABLET);
163
m_pSys->pPC->SelectDuplexPrinting (DUPLEXMODE_BOOK);
167
m_pSys->pPC->SelectDuplexPrinting (DUPLEXMODE_NONE);
169
float fWidth = (float) m_cupsHeader.PageSize[0] / (float) 72.0;
170
float fHeight = (float) m_cupsHeader.PageSize[1] / (float) 72.0;
171
m_pSys->MapPaperSize (fWidth, fHeight);
173
m_pSys->pPC->SetPixelsPerRow (m_cupsHeader.cupsWidth, m_cupsHeader.cupsWidth);
175
// Now set all the printer hints
176
if (m_cupsHeader.cupsInteger[0])
178
// Papersize as PCL id
183
for (int i = 1; i < 6; i++)
185
eHint = (PRINTER_HINT) i;
186
iValue = m_cupsHeader.cupsInteger[i];
189
m_pSys->pPC->SetPrinterHint (eHint, iValue);
193
// Turn off bi-di support.
194
m_pSys->ResetIOMode (FALSE, FALSE);
196
// Create a new Job object
197
m_pSys->pJob = new Job (m_pSys->pPC);
198
if (m_pSys->pJob->constructor_error != NO_ERROR)
200
BUG ("ERROR: Unable to create Job object, error = %d\n",
201
m_pSys->pJob->constructor_error);
207
int HPCups::ProcessJob (int argc, char **argv)
210
cups_raster_t *cups_raster;
214
// Check commandline.
216
if (argc < 6 || argc > 7)
218
BUG ("ERROR: %s job-id user title copies options [file]\n", *argv);
222
if (initServices (argv[1]) != 0)
226
if (initContext (argv) != 0)
231
// Open input stream if it is not stdin
234
m_fd = open (argv[6], O_RDONLY);
237
BUG ("ERROR: Unable to open raster file %s\n", argv[6]);
242
cups_raster = cupsRasterOpen (m_fd, CUPS_RASTER_READ);
243
if (cups_raster == NULL)
245
BUG ("cupsRasterOpen failed, fd = %d\n", m_fd);
249
iStatus = processRasterData (cups_raster);
250
cupsRasterClose (cups_raster);
255
int HPCups::initServices (char *szJobId)
257
m_pSys = new UXServices ();
258
if (m_pSys->constructor_error != NO_ERROR)
260
BUG ("Services object failed, error = %d\n", m_pSys->constructor_error);
263
m_pSys->OutputPath = STDOUT_FILENO;
264
m_pSys->m_iLogLevel = m_iLogLevel;
266
// Does the user wish to send printer ready data to a disk file
267
if (m_iLogLevel & SAVE_PCL_FILE)
270
sprintf (szFileName, "/tmp/hpcups_%s.out", szJobId);
271
m_pSys->outfp = fopen (szFileName, "w");
274
chmod (szFileName, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
281
int HPCups::initContext (char **argv)
283
DRIVER_ERROR err = NO_ERROR;
287
m_pSys->pPC = new PrintContext (m_pSys, 0, 0);
290
* If bi-di fails, we still want to continue, so ignore this error.
291
* The failure can also be because of missing plugin. If this printer
292
* requires the plugin, it will be handled later, but if it is optional
293
* then we want to continue.
296
if (m_pSys->pPC->constructor_error > 0 &&
297
m_pSys->pPC->constructor_error != PLUGIN_LIBRARY_MISSING &&
298
m_pSys->DisplayStatus != DISPLAY_PRINTING_CANCELED)
300
BUG("PrintContext creation failed, error = %d", m_pSys->pPC->constructor_error);
305
* Check for any warnings, but ignore printmode mismatch warning.
306
* This will happen on monochrome printers. We will select the proper
310
if (m_pSys->pPC->constructor_error < 0 &&
311
m_pSys->pPC->constructor_error != WARN_MODE_MISMATCH)
313
BUG ("WARNING: %s\n", m_pSys->GetDriverMessage (m_pSys->pPC->constructor_error));
314
switch (m_pSys->pPC->constructor_error)
316
case WARN_LOW_INK_BOTH_PENS:
317
case WARN_LOW_INK_BLACK:
318
case WARN_LOW_INK_COLOR:
319
case WARN_LOW_INK_PHOTO:
320
case WARN_LOW_INK_GREY:
321
case WARN_LOW_INK_BLACK_PHOTO:
322
case WARN_LOW_INK_COLOR_PHOTO:
323
case WARN_LOW_INK_GREY_PHOTO:
324
case WARN_LOW_INK_COLOR_GREY:
325
case WARN_LOW_INK_COLOR_GREY_PHOTO:
326
case WARN_LOW_INK_COLOR_BLACK_PHOTO:
327
case WARN_LOW_INK_CYAN:
328
case WARN_LOW_INK_MAGENTA:
329
case WARN_LOW_INK_YELLOW:
330
case WARN_LOW_INK_MULTIPLE_PENS:
332
BUG ("STATE: marker-supply-low-warning\n");
336
BUG ("STATE: -marker-supply-low-warning");
340
// Select the device class
341
ppd = ppdOpenFile (getenv ("PPD"));
344
BUG ("ERROR: Unable to open ppd file %s\n", getenv ("PPD"));
347
if ((attr = ppdFindAttr (ppd, "cupsModelName", NULL)) == NULL ||
348
(attr && attr->value == NULL))
350
BUG ("ERROR: Required cupsModelName is missing in ppd file\n");
354
err = m_pSys->pPC->SelectDevice (attr->value);
355
if (err == PLUGIN_LIBRARY_MISSING)
358
SendDbusMessage (getenv ("DEVICE_URI"), getenv ("PRINTER"),
359
EVENT_PRINT_FAILED_MISSING_PLUGIN,
360
argv[2], atoi (argv[1]), argv[3]);
361
BUG ("ERROR: unable to set device = %s, err = %d\n", attr->value, err);
367
int HPCups::processRasterData (cups_raster_t *cups_raster)
369
DRIVER_ERROR err = NO_ERROR;
378
BYTE *kRaster = NULL;
379
BYTE *rgbRaster = NULL;
381
while (cupsRasterReadHeader2 (cups_raster, &m_cupsHeader))
386
pKRGBRaster = new BYTE[m_cupsHeader.cupsBytesPerLine];
387
iStatus = initPrintJob ();
392
if (m_cupsHeader.cupsColorSpace == CUPS_CSPACE_RGBW)
394
kRaster = new BYTE[m_cupsHeader.cupsWidth];
395
rgbRaster = new BYTE[m_cupsHeader.cupsWidth * 3];
396
if (kRaster == NULL || rgbRaster == NULL)
398
BUG ("Memory allocation error\n");
402
memset (kRaster, 0, m_cupsHeader.cupsWidth);
403
memset (rgbRaster, 0xFF, m_cupsHeader.cupsWidth * 3);
405
else if (m_cupsHeader.cupsColorSpace == CUPS_CSPACE_K)
407
kRaster = pKRGBRaster;
411
if (m_cupsHeader.cupsColorSpace == CUPS_CSPACE_K)
413
kRaster = pKRGBRaster;
416
else if (m_cupsHeader.cupsColorSpace != CUPS_CSPACE_RGBW)
418
rgbRaster = pKRGBRaster;
420
if (m_iLogLevel & SAVE_INPUT_RASTERS)
423
sprintf (szFileName, "/tmp/hpcupsc_%d.bmp", iPageNum);
424
if (m_cupsHeader.cupsColorSpace == CUPS_CSPACE_RGBW ||
425
m_cupsHeader.cupsColorSpace == CUPS_CSPACE_RGB)
427
cfp = fopen (szFileName, "w");
428
chmod (szFileName, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
430
if (m_cupsHeader.cupsColorSpace == CUPS_CSPACE_RGBW ||
431
m_cupsHeader.cupsColorSpace == CUPS_CSPACE_K)
433
szFileName[11] = 'k';
434
kfp = fopen (szFileName, "w");
435
chmod (szFileName, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
437
bitmap.WriteBMPHeader (cfp, m_cupsHeader.cupsWidth, m_cupsHeader.cupsHeight, COLOR_RASTER);
438
bitmap.WriteBMPHeader (kfp, m_cupsHeader.cupsWidth, m_cupsHeader.cupsHeight, BLACK_RASTER);
440
m_pSys->SendPreviousPage ();
441
for (int y = 0; y < (int) m_cupsHeader.cupsHeight; y++)
443
cupsRasterReadPixels (cups_raster, pKRGBRaster, m_cupsHeader.cupsBytesPerLine);
444
color_raster = rgbRaster;
445
black_raster = kRaster;
446
if (isBlankRaster (pKRGBRaster, (int) m_cupsHeader.cupsBytesPerLine))
451
doKSeparation (pKRGBRaster, black_raster, color_raster);
452
err = m_pSys->pJob->SendRasters (black_raster, color_raster);
458
bitmap.WriteBMPRaster (cfp, color_raster, m_cupsHeader.cupsWidth, COLOR_RASTER);
459
bitmap.WriteBMPRaster (kfp, black_raster, m_cupsHeader.cupsWidth/8, BLACK_RASTER);
461
iStatus = (int) m_pSys->pJob->NewPage ();
469
delete [] pKRGBRaster;
471
if (kRaster && m_cupsHeader.cupsColorSpace != CUPS_CSPACE_K)
475
if (m_cupsHeader.cupsColorSpace == CUPS_CSPACE_RGBW)
490
void HPCups::doKSeparation (BYTE *pKRGBRaster, BYTE *black_raster, BYTE *color_raster)
493
static BYTE pixel_value[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
495
if (black_raster == NULL || m_cupsHeader.cupsColorSpace != CUPS_CSPACE_RGBW)
501
BYTE *pIn = pKRGBRaster;
504
BYTE *rgb = color_raster;
505
BYTE *black = black_raster;
506
memset (black_raster, 0, m_cupsHeader.cupsWidth);
508
for (unsigned int i = 0; i < m_cupsHeader.cupsWidth; i++)
515
if (b != 0 && b != 0xFF)
523
kVal |= (b == 0) ? pixel_value[k] : 0;
540
BOOL HPCups::isBlankRaster (BYTE *pRaster, int iNumBytes)
546
if (*pRaster == 0xFF &&
547
!(memcmp (pRaster + 1, pRaster, iNumBytes - 1)))
554
void HPCups::printcupsHeader ()
556
BUG("DEBUG: startPage...\n");
557
BUG("DEBUG: MediaClass = \"%s\"\n", m_cupsHeader.MediaClass);
558
BUG("DEBUG: MediaColor = \"%s\"\n", m_cupsHeader.MediaColor);
559
BUG("DEBUG: MediaType = \"%s\"\n", m_cupsHeader.MediaType);
560
BUG("DEBUG: OutputType = \"%s\"\n", m_cupsHeader.OutputType);
561
BUG("DEBUG: AdvanceDistance = %d\n", m_cupsHeader.AdvanceDistance);
562
BUG("DEBUG: AdvanceMedia = %d\n", m_cupsHeader.AdvanceMedia);
563
BUG("DEBUG: Collate = %d\n", m_cupsHeader.Collate);
564
BUG("DEBUG: CutMedia = %d\n", m_cupsHeader.CutMedia);
565
BUG("DEBUG: Duplex = %d\n", m_cupsHeader.Duplex);
566
BUG("DEBUG: HWResolution = [ %d %d ]\n", m_cupsHeader.HWResolution[0], m_cupsHeader.HWResolution[1]);
567
BUG("DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n",
568
m_cupsHeader.ImagingBoundingBox[0], m_cupsHeader.ImagingBoundingBox[1],
569
m_cupsHeader.ImagingBoundingBox[2], m_cupsHeader.ImagingBoundingBox[3]);
570
BUG("DEBUG: InsertSheet = %d\n", m_cupsHeader.InsertSheet);
571
BUG("DEBUG: Jog = %d\n", m_cupsHeader.Jog);
572
BUG("DEBUG: LeadingEdge = %d\n", m_cupsHeader.LeadingEdge);
573
BUG("DEBUG: Margins = [ %d %d ]\n", m_cupsHeader.Margins[0], m_cupsHeader.Margins[1]);
574
BUG("DEBUG: ManualFeed = %d\n", m_cupsHeader.ManualFeed);
575
BUG("DEBUG: MediaPosition = %d\n", m_cupsHeader.MediaPosition);
576
BUG("DEBUG: MediaWeight = %d\n", m_cupsHeader.MediaWeight);
577
BUG("DEBUG: MirrorPrint = %d\n", m_cupsHeader.MirrorPrint);
578
BUG("DEBUG: NegativePrint = %d\n", m_cupsHeader.NegativePrint);
579
BUG("DEBUG: NumCopies = %d\n", m_cupsHeader.NumCopies);
580
BUG("DEBUG: Orientation = %d\n", m_cupsHeader.Orientation);
581
BUG("DEBUG: OutputFaceUp = %d\n", m_cupsHeader.OutputFaceUp);
582
BUG("DEBUG: PageSize = [ %d %d ]\n", m_cupsHeader.PageSize[0], m_cupsHeader.PageSize[1]);
583
BUG("DEBUG: Separations = %d\n", m_cupsHeader.Separations);
584
BUG("DEBUG: TraySwitch = %d\n", m_cupsHeader.TraySwitch);
585
BUG("DEBUG: Tumble = %d\n", m_cupsHeader.Tumble);
586
BUG("DEBUG: cupsWidth = %d\n", m_cupsHeader.cupsWidth);
587
BUG("DEBUG: cupsHeight = %d\n", m_cupsHeader.cupsHeight);
588
BUG("DEBUG: cupsMediaType = %d\n", m_cupsHeader.cupsMediaType);
589
BUG("DEBUG: cupsRowStep = %d\n", m_cupsHeader.cupsRowStep);
590
BUG("DEBUG: cupsBitsPerColor = %d\n", m_cupsHeader.cupsBitsPerColor);
591
BUG("DEBUG: cupsBitsPerPixel = %d\n", m_cupsHeader.cupsBitsPerPixel);
592
BUG("DEBUG: cupsBytesPerLine = %d\n", m_cupsHeader.cupsBytesPerLine);
593
BUG("DEBUG: cupsColorOrder = %d\n", m_cupsHeader.cupsColorOrder);
594
BUG("DEBUG: cupsColorSpace = %d\n", m_cupsHeader.cupsColorSpace);
595
BUG("DEBUG: cupsCompression = %d\n", m_cupsHeader.cupsCompression);
596
BUG("DEBUG: cupsPageSizeName = %s\n", m_cupsHeader.cupsPageSizeName);
597
BUG("DEBUG: cupsInteger0 = %d\n", m_cupsHeader.cupsInteger[0]); // Page Size
598
BUG("DEBUG: cupsInteger1 = %d\n", m_cupsHeader.cupsInteger[1]); // Speedmech
599
BUG("DEBUG: cupsInteger2 = %d\n", m_cupsHeader.cupsInteger[2]); // Dry time
600
BUG("DEBUG: cupsInteger3 = %d\n", m_cupsHeader.cupsInteger[3]); // Filesize
601
BUG("DEBUG: cupsInteger4 = %d\n", m_cupsHeader.cupsInteger[4]); // Redeye
602
BUG("DEBUG: cupsInteger5 = %d\n", m_cupsHeader.cupsInteger[5]); // Photofix
605
void HPCups::CancelJob ()
607
BYTE byResetLIDIL[] = {0x24, 0x00, 0x10, 0x00, 0x06, 0x00, 0x00, 0x00,
608
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x24};
612
memset (buffer, 0, size);
613
pt = m_pSys->pPC->SelectedDevice();
622
memcpy (buffer + 4080, byResetLIDIL, 16);
623
m_pSys->ToDevice ((const BYTE *) buffer, &size);
630
memcpy (buffer + 4087, "\x1B%-12345X", 9);
631
m_pSys->ToDevice ((const BYTE *) buffer, &size);
635
m_pSys->OutputPath = -1; // so no more output is sent to the printer
636
if (m_pSys->pJob != NULL)
638
if (m_pSys->pPC != NULL)
644
static HPCups hpCups;
645
void CancelPrintJob (int sig)
651
int main (int argc, char **argv)
653
int iRet = hpCups.ProcessJob (argc, argv);
654
BUG("hpcups: returning status %d from main", iRet);