1/* 2 * $Id: ijsgutenprint.c,v 1.23 2010/07/19 11:14:04 rlk Exp $ 3 * 4 * IJS server for Gutenprint. 5 * 6 * Copyright 2001 Robert Krawitz (rlk@alum.mit.edu) 7 * 8 * Originally written by Russell Lang, copyright assigned to Robert Krawitz. 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the Free 12 * Software Foundation; either version 2 of the License, or (at your option) 13 * any later version. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 * for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 23 * 24 * Revision History: 25 * 26 * See ChangeLog 27 */ 28 29#ifdef HAVE_CONFIG_H 30#include <config.h> 31#endif 32#include <gutenprint/gutenprint.h> 33#include <stdio.h> 34#include <stdlib.h> 35#include <string.h> 36#include <unistd.h> 37#include <locale.h> 38#include <ijs.h> 39#include <ijs_server.h> 40#include <errno.h> 41#include <gutenprint/gutenprint-intl-internal.h> 42 43 44static int suppress_messages = 0; 45volatile int SDEBUG = 1; 46static int job_aborted = 0; 47 48#define STP_DEBUG(x) \ 49do \ 50{ \ 51 if (!suppress_messages) \ 52 fprintf(stderr, "DEBUG: "); \ 53 if (!suppress_messages) \ 54 x; \ 55} while (0) 56 57typedef struct _GutenprintParamList GutenprintParamList; 58 59struct _GutenprintParamList { 60 GutenprintParamList *next; 61 char *key; 62 char *value; 63 int value_size; 64}; 65 66typedef struct _IMAGE 67{ 68 IjsServerCtx *ctx; 69 stp_vars_t *v; 70 char *filename; /* OutputFile */ 71 int fd; /* OutputFD + 1 (so that 0 is invalid) */ 72 int width; /* pixels */ 73 int height; /* pixels */ 74 int bps; /* bytes per sample */ 75 int n_chan; /* number of channels */ 76 int xres; /* dpi */ 77 int yres; 78 int output_type; 79 int left_margin; 80 int right_margin; 81 int top_margin; 82 int bottom_margin; 83 int monochrome_flag; /* for monochrome output */ 84 int row; /* row number in buffer */ 85 int row_width; /* length of a row */ 86 char *row_buf; /* buffer for raster */ 87 double total_bytes; /* total size of raster */ 88 double bytes_left; /* bytes remaining to be read */ 89 GutenprintParamList *params; 90} IMAGE; 91 92static const char DeviceGray[] = "DeviceGray"; 93static const char DeviceRGB[] = "DeviceRGB"; 94static const char DeviceCMYK[] = "DeviceCMYK"; 95 96static const char *version_id; 97static int version_is_ok = 1; 98#define VERSION_MISMATCH "\ 99ERROR: ijsgutenprint: the version of Gutenprint software installed (%s)\n\ 100ERROR: ijsgutenprint: does not match the PPD file (%s). If you have upgraded your version\n\ 101ERROR: ijsgutenprint: of Gutenprint recently, you must reinstall all printer queues.\n\ 102ERROR: ijsgutenprint: Please refer to your vendor's documentation or the ``foomatic-ppdfile''\n\ 103ERROR: ijsgutenprint: command for instructions.\n\ 104ERROR: ijsgutenprint: the version of Gutenprint software installed (%s) does not match the PPD file (%s).\n" 105 106const char *gutenprint_ppd_version = NULL; 107static int ppd_mode = 0; /* Use PPD-style margins */ 108 109static stp_string_list_t *option_remap_list = NULL; 110static int print_messages_as_errors = 0; 111 112static double page_bytes_printed = 0; 113static double total_bytes_printed = 0; 114 115static char * 116c_strdup(const char *s) 117{ 118 char *ret = stp_malloc(strlen(s) + 1); 119 strcpy(ret, s); 120 return ret; 121} 122 123static int 124image_init(IMAGE *img, IjsPageHeader *ph) 125{ 126 img->width = ph->width; 127 img->height = ph->height; 128 img->bps = ph->bps; 129 img->n_chan = ph->n_chan; 130 img->xres = ph->xres; 131 img->yres = ph->yres; 132 133 img->row = -1; 134 img->row_width = (ph->n_chan * ph->bps * ph->width + 7) >> 3; 135 if (img->row_buf) 136 stp_free(img->row_buf); 137 img->row_buf = (char *)stp_malloc(img->row_width); 138 STP_DEBUG(fprintf(stderr, "ijsgutenprint: image_init\n")); 139 STP_DEBUG(fprintf(stderr, 140 "ijsgutenprint: ph width %d height %d bps %d n_chan %d xres %f yres %f\n", 141 ph->width, ph->height, ph->bps, ph->n_chan, ph->xres, 142 ph->yres)); 143 144 stp_set_string_parameter(img->v, "ChannelBitDepth", "8"); 145 if ((img->bps == 1) && (img->n_chan == 1) && 146 (strncmp(ph->cs, DeviceGray, strlen(DeviceGray)) == 0)) 147 { 148 STP_DEBUG(fprintf(stderr, "ijsgutenprint: output monochrome\n")); 149 stp_set_string_parameter(img->v, "InputImageType", "Whitescale"); 150 stp_set_string_parameter(img->v, "PrintingMode", "BW"); 151 stp_set_string_parameter(img->v, "ColorCorrection", "Threshold"); 152 img->monochrome_flag = 1; 153 /* 8-bit greyscale */ 154 } 155 else if (img->bps == 8 || img->bps == 16) 156 { 157 if (img->bps == 8) 158 stp_set_string_parameter(img->v, "ChannelBitDepth", "8"); 159 else 160 stp_set_string_parameter(img->v, "ChannelBitDepth", "16"); 161 if ((img->n_chan == 1) && 162 (strncmp(ph->cs, DeviceGray, strlen(DeviceGray)) == 0)) 163 { 164 STP_DEBUG(fprintf(stderr, "ijsgutenprint: output gray\n")); 165 stp_set_string_parameter(img->v, "InputImageType", "Whitescale"); 166 stp_set_string_parameter(img->v, "PrintingMode", "BW"); 167 img->monochrome_flag = 0; 168 /* 8/16-bit greyscale */ 169 } 170 else if ((img->n_chan == 3) && 171 (strncmp(ph->cs, DeviceRGB, strlen(DeviceRGB)) == 0)) 172 { 173 STP_DEBUG(fprintf(stderr, "ijsgutenprint: output color\n")); 174 stp_set_string_parameter(img->v, "InputImageType", "RGB"); 175 stp_set_string_parameter(img->v, "PrintingMode", "Color"); 176 img->monochrome_flag = 0; 177 /* 24/48-bit RGB colour */ 178 } 179 else if ((img->n_chan == 4) && 180 (strncmp(ph->cs, DeviceCMYK, strlen(DeviceCMYK)) == 0)) 181 { 182 STP_DEBUG(fprintf(stderr, "ijsgutenprint: output CMYK\n")); 183 stp_set_string_parameter(img->v, "InputImageType", "CMYK"); 184 stp_set_string_parameter(img->v, "PrintingMode", "Color"); 185 img->monochrome_flag = 0; 186 /* 32/64-bit CMYK colour */ 187 } 188 } 189 else 190 { 191 fprintf(stderr, "ERROR: ijsgutenprint: Bad color space: bps %d channels %d space %s\n", 192 img->bps, img->n_chan, ph->cs); 193 /* unsupported */ 194 return -1; 195 } 196 197 if (img->row_buf == NULL) 198 { 199 fprintf(stderr, "ERROR: ijsgutenprint: No row buffer\n"); 200 return -1; 201 } 202 203 return 0; 204} 205 206static void 207image_finish(IMAGE *img) 208{ 209 if (img->row_buf) 210 stp_free(img->row_buf); 211 img->row_buf = NULL; 212} 213 214static double 215get_float(const char *str, const char *name, double *pval) 216{ 217 float new_value; 218 int status = 0; 219 /* Force locale to "C", because decimal numbers coming from the IJS 220 client are always with a decimal point, nver with a decimal comma */ 221 setlocale(LC_ALL, "C"); 222 if (sscanf(str, "%f", &new_value) == 1) 223 *pval = new_value; 224 else 225 { 226 fprintf(stderr, "ERROR: ijsgutenprint: Unable to parse parameter %s=%s (expect a number)\n", 227 name, str); 228 status = -1; 229 } 230 setlocale(LC_ALL, ""); 231 return status; 232} 233 234static int 235get_int(const char *str, const char *name, int *pval) 236{ 237 int new_value; 238 int status = 0; 239 /* Force locale to "C", because decimal numbers sent to the IJS 240 client must have a decimal point, nver a decimal comma */ 241 setlocale(LC_ALL, "C"); 242 if (sscanf(str, "%d", &new_value) == 1) 243 *pval = new_value; 244 else 245 { 246 fprintf(stderr, "ERROR: ijsgutenprint: Unable to parse parameter %s=%s (expect a number)\n", 247 name, str); 248 status = -1; 249 } 250 setlocale(LC_ALL, ""); 251 return status; 252} 253 254static int 255parse_wxh_internal(const char *val, int size, double *pw, double *ph) 256{ 257 char buf[256]; 258 char *tail; 259 int i; 260 261 for (i = 0; i < size; i++) 262 if (val[i] == 'x') 263 break; 264 265 if (i + 1 >= size) 266 return IJS_ESYNTAX; 267 268 if (i >= sizeof(buf)) 269 return IJS_EBUF; 270 271 memcpy (buf, val, i); 272 buf[i] = 0; 273 *pw = strtod (buf, &tail); 274 if (tail == buf) 275 return IJS_ESYNTAX; 276 277 if (size - i > sizeof(buf)) 278 return IJS_EBUF; 279 280 memcpy (buf, val + i + 1, size - i - 1); 281 buf[size - i - 1] = 0; 282 *ph = strtod (buf, &tail); 283 if (tail == buf) 284 return IJS_ESYNTAX; 285 286 return 0; 287} 288 289/* A C implementation of /^(\d\.+\-eE)+x(\d\.+\-eE)+$/ */ 290static int 291gutenprint_parse_wxh (const char *val, int size, double *pw, double *ph) 292{ 293 /* Force locale to "C", because decimal numbers coming from the IJS 294 client are always with a decimal point, nver with a decimal comma */ 295 int status; 296 setlocale(LC_ALL, "C"); 297 status = parse_wxh_internal(val, size, pw, ph); 298 setlocale(LC_ALL, ""); 299 return status; 300} 301 302/** 303 * gutenprint_find_key: Search parameter list for key. 304 * 305 * @key: key to look up 306 * 307 * Return value: GutenprintParamList entry matching @key, or NULL. 308 **/ 309static GutenprintParamList * 310gutenprint_find_key (GutenprintParamList *pl, const char *key) 311{ 312 GutenprintParamList *curs; 313 314 for (curs = pl; curs != NULL; curs = curs->next) 315 { 316 if (!strcmp (curs->key, key)) 317 return curs; 318 } 319 return NULL; 320} 321 322static int 323gutenprint_status_cb (void *status_cb_data, 324 IjsServerCtx *ctx, 325 IjsJobId job_id) 326{ 327 return 0; 328} 329 330static const char * 331list_all_parameters(void) 332{ 333 static char *param_string = NULL; 334 size_t param_length = 0; 335 size_t offset = 0; 336 if (param_length == 0) 337 { 338 stp_string_list_t *sl = stp_string_list_create(); 339 int printer_count = stp_printer_model_count(); 340 int i; 341 stp_string_list_add_string(sl, "PrintableArea", NULL); 342 stp_string_list_add_string(sl, "Dpi", NULL); 343 stp_string_list_add_string(sl, "PrintableTopLeft", NULL); 344 stp_string_list_add_string(sl, "DeviceManufacturer", NULL); 345 stp_string_list_add_string(sl, "DeviceModel", NULL); 346 stp_string_list_add_string(sl, "PageImageFormat", NULL); 347 stp_string_list_add_string(sl, "OutputFile", NULL); 348 stp_string_list_add_string(sl, "OutputFd", NULL); 349 stp_string_list_add_string(sl, "PaperSize", NULL); 350 stp_string_list_add_string(sl, "MediaName", NULL); 351 stp_string_list_add_string(sl, "STP_VERSION", NULL); 352 for (i = 0; i < printer_count; i++) 353 { 354 const stp_printer_t *printer = stp_get_printer_by_index(i); 355 stp_parameter_list_t params = 356 stp_get_parameter_list(stp_printer_get_defaults(printer)); 357 size_t count = stp_parameter_list_count(params); 358 int j; 359 if (strcmp(stp_printer_get_family(printer), "ps") == 0 || 360 strcmp(stp_printer_get_family(printer), "raw") == 0) 361 continue; 362 for (j = 0; j < count; j++) 363 { 364 const stp_parameter_t *param = 365 stp_parameter_list_param(params, j); 366 char *tmp = 367 stp_malloc(strlen(param->name) + strlen("STP_") + 1); 368 sprintf(tmp, "STP_%s", param->name); 369 if ((param->p_level < STP_PARAMETER_LEVEL_ADVANCED4) && 370 (param->p_type != STP_PARAMETER_TYPE_RAW) && 371 (param->p_type != STP_PARAMETER_TYPE_FILE) && 372 (!param->read_only) && 373 (strcmp(param->name, "Resolution") != 0) && 374 (strcmp(param->name, "PageSize") != 0) && 375 (!stp_string_list_is_present(sl, tmp))) 376 { 377 sprintf(tmp, "STP_%s", param->name); 378 stp_string_list_add_string(sl, tmp, NULL); 379 if ((param->p_type == STP_PARAMETER_TYPE_DOUBLE || 380 param->p_type == STP_PARAMETER_TYPE_DIMENSION) && 381 !param->read_only && param->is_active && 382 !param->is_mandatory) 383 { 384 char *tmp1 = 385 stp_malloc(strlen(param->name) + strlen("STP_Enable") + 1); 386 sprintf(tmp1, "STP_Enable%s", param->name); 387 stp_string_list_add_string(sl, tmp1, NULL); 388 stp_free(tmp1); 389 } 390 } 391 stp_free(tmp); 392 } 393 stp_parameter_list_destroy(params); 394 } 395 for (i = 0; i < stp_string_list_count(sl); i++) 396 param_length += strlen(stp_string_list_param(sl, i)->name) + 1; 397 param_string = stp_malloc(param_length); 398 for (i = 0; i < stp_string_list_count(sl); i++) 399 { 400 stp_param_string_t *param = stp_string_list_param(sl, i); 401 strcpy(param_string + offset, param->name); 402 offset += strlen(param->name) + 1; 403 param_string[offset - 1] = ','; 404 } 405 if (offset != param_length) 406 { 407 fprintf(stderr, "ERROR: ijsgutenprint: Bad string length %lu != %lu!\n", 408 (unsigned long) offset, 409 (unsigned long) param_length); 410 exit(1); 411 } 412 param_string[param_length - 1] = '\0'; 413 } 414 return param_string; 415} 416 417 418static int 419gutenprint_list_cb (void *list_cb_data, 420 IjsServerCtx *ctx, 421 IjsJobId job_id, 422 char *val_buf, 423 int val_size) 424{ 425 const char *param_list = list_all_parameters(); 426 int size = strlen (param_list); 427 STP_DEBUG(fprintf(stderr, "ijsgutenprint: gutenprint_list_cb: %s\n", param_list)); 428 429 if (size > val_size) 430 return IJS_EBUF; 431 432 memcpy (val_buf, param_list, size); 433 return size; 434} 435 436static int 437gutenprint_enum_cb (void *enum_cb_data, 438 IjsServerCtx *ctx, 439 IjsJobId job_id, 440 const char *key, 441 char *val_buf, 442 int val_size) 443{ 444 const char *val = NULL; 445 STP_DEBUG(fprintf(stderr, "ijsgutenprint: gutenprint_enum_cb: key=%s\n", key)); 446 if (!strcmp (key, "ColorSpace")) 447 val = "DeviceRGB,DeviceGray,DeviceCMYK"; 448 else if (!strcmp (key, "DeviceManufacturer")) 449 val = "Gutenprint"; 450 else if (!strcmp (key, "DeviceModel")) 451 val = "gutenprint"; 452 else if (!strcmp (key, "PageImageFormat")) 453 val = "Raster"; 454 else if (!strcmp (key, "BitsPerSample")) 455 val = "8,16"; 456 else if (!strcmp (key, "ByteSex")) 457 { 458#if __BYTE_ORDER == __LITTLE_ENDIAN 459 val="little-endian"; 460#else 461 val="big-endian"; 462#endif 463 } 464 465 if (val == NULL) 466 return IJS_EUNKPARAM; 467 else 468 { 469 int size = strlen (val); 470 471 if (size > val_size) 472 return IJS_EBUF; 473 memcpy (val_buf, val, size); 474 return size; 475 } 476} 477 478static int 479gutenprint_get_cb (void *get_cb_data, 480 IjsServerCtx *ctx, 481 IjsJobId job_id, 482 const char *key, 483 char *val_buf, 484 int val_size) 485{ 486 IMAGE *img = (IMAGE *)get_cb_data; 487 stp_vars_t *v = img->v; 488 const stp_printer_t *printer = stp_get_printer(v); 489 GutenprintParamList *pl = img->params; 490 GutenprintParamList *curs; 491 const char *val = NULL; 492 char buf[256]; 493 494 STP_DEBUG(fprintf(stderr, "ijsgutenprint: gutenprint_get_cb: %s\n", key)); 495 if (!printer) 496 { 497 if (strlen(stp_get_driver(v)) == 0) 498 fprintf(stderr, "ERROR: ijsgutenprint: Printer must be specified with -sDeviceModel\n"); 499 else 500 fprintf(stderr, "ERROR: ijsgutenprint: Printer %s is not a known model\n", 501 stp_get_driver(v)); 502 return IJS_EUNKPARAM; 503 } 504 curs = gutenprint_find_key (pl, key); 505 if (curs != NULL) 506 { 507 if (curs->value_size > val_size) 508 return IJS_EBUF; 509 memcpy (val_buf, curs->value, curs->value_size); 510 return curs->value_size; 511 } 512 513 if (!strcmp(key, "PrintableArea")) 514 { 515 int l, r, b, t; 516 int h, w; 517 if (ppd_mode) 518 { 519 stp_get_media_size(v, &w, &h); 520 stp_get_maximum_imageable_area(v, &l, &r, &b, &t); 521 if (l < 0) 522 l = 0; 523 if (r > w) 524 r = w; 525 if (t < 0) 526 t = 0; 527 if (b > h) 528 b = h; 529 } 530 else 531 stp_get_imageable_area(v, &l, &r, &b, &t); 532 533 534 h = b - t; 535 w = r - l; 536 /* Force locale to "C", because decimal numbers sent to the IJS 537 client must have a decimal point, nver a decimal comma */ 538 setlocale(LC_ALL, "C"); 539 sprintf(buf, "%gx%g", (double) w / 72.0, (double) h / 72.0); 540 setlocale(LC_ALL, ""); 541 STP_DEBUG(fprintf(stderr, "ijsgutenprint: PrintableArea %d %d %s\n", h, w, buf)); 542 val = buf; 543 } 544 else if (!strcmp(key, "Dpi")) 545 { 546 int x, y; 547 stp_describe_resolution(v, &x, &y); 548 /* Force locale to "C", because decimal numbers sent to the IJS 549 client must have a decimal point, nver a decimal comma */ 550 setlocale(LC_ALL, "C"); 551 sprintf(buf, "%d", x); 552 setlocale(LC_ALL, ""); 553 STP_DEBUG(fprintf(stderr, "ijsgutenprint: Dpi %d %d (%d) %s\n", x, y, x, buf)); 554 val = buf; 555 } 556 else if (!strcmp(key, "PrintableTopLeft")) 557 { 558 int l, r, b, t; 559 int h, w; 560 stp_get_media_size(v, &w, &h); 561 if (ppd_mode) 562 { 563 stp_get_maximum_imageable_area(v, &l, &r, &b, &t); 564 if (l < 0) 565 l = 0; 566 if (r > w) 567 r = w; 568 if (t < 0) 569 t = 0; 570 if (b > h) 571 b = h; 572 } 573 else 574 stp_get_imageable_area(v, &l, &r, &b, &t); 575 /* Force locale to "C", because decimal numbers sent to the IJS 576 client must have a decimal point, nver a decimal comma */ 577 setlocale(LC_ALL, "C"); 578 sprintf(buf, "%gx%g", (double) l / 72.0, (double) t / 72.0); 579 setlocale(LC_ALL, ""); 580 STP_DEBUG(fprintf(stderr, "ijsgutenprint: PrintableTopLeft %d %d %s\n", t, l, buf)); 581 val = buf; 582 } 583 else if (!strcmp (key, "DeviceManufacturer")) 584 val = "Gutenprint"; 585 else if (!strcmp (key, "DeviceModel")) 586 val = stp_get_driver(img->v); 587 else if (!strcmp (key, "PageImageFormat")) 588 val = "Raster"; 589 590 if (val == NULL) 591 return IJS_EUNKPARAM; 592 else 593 { 594 int size = strlen (val); 595 596 if (size > val_size) 597 return IJS_EBUF; 598 memcpy (val_buf, val, size); 599 return size; 600 } 601} 602 603static void 604print_debug_setcb(const char *key, const char *value, int value_size) 605{ 606 fprintf (stderr, "ijsgutenprint: gutenprint_set_cb: %s='", key); 607 fwrite (value, 1, value_size, stderr); 608 fputs ("'\n", stderr); 609} 610 611static int 612gutenprint_set_cb (void *set_cb_data, IjsServerCtx *ctx, IjsJobId jobid, 613 const char *key, const char *value, int value_size) 614{ 615 int code = 0; 616 char vbuf[256]; 617 int i; 618 double z = 0; 619 IMAGE *img = (IMAGE *)set_cb_data; 620 STP_DEBUG(print_debug_setcb(key, value, value_size)); 621 if (value_size > sizeof(vbuf)-1) 622 return -1; 623 memset(vbuf, 0, sizeof(vbuf)); 624 memcpy(vbuf, value, value_size); 625 626 if (strcmp(key, "OutputFile") == 0) 627 { 628 if (img->filename) 629 stp_free(img->filename); 630 img->filename = c_strdup(vbuf); 631 } 632 else if (strcmp(key, "OutputFD") == 0) 633 { 634 /* Force locale to "C", because decimal numbers sent to the IJS 635 client must have a decimal point, nver a decimal comma */ 636 setlocale(LC_ALL, "C"); 637 img->fd = atoi(vbuf) + 1; 638 setlocale(LC_ALL, ""); 639 } 640 else if (strcmp(key, "DeviceManufacturer") == 0) 641 ; /* We don't care who makes it */ 642 else if (strcmp(key, "DeviceModel") == 0) 643 { 644 const stp_printer_t *printer = stp_get_printer_by_driver(vbuf); 645 stp_set_driver(img->v, vbuf); 646 if (printer && 647 strcmp(stp_printer_get_family(printer), "ps") != 0 && 648 strcmp(stp_printer_get_family(printer), "raw") != 0) 649 { 650 stp_set_printer_defaults(img->v, printer); 651 /* Reset JobMode to "Job" */ 652 stp_set_string_parameter(img->v, "JobMode", "Job"); 653 } 654 else 655 { 656 fprintf(stderr, "ERROR: ijsgutenprint: unknown DeviceModel %s\n", vbuf); 657 code = IJS_ERANGE; 658 } 659 } 660 else if (strcmp(key, "TopLeft") == 0) 661 { 662 int l, r, b, t, pw, ph; 663 double w, h; 664 stp_get_media_size(img->v, &pw, &ph); 665 if (ppd_mode) 666 { 667 stp_get_maximum_imageable_area(img->v, &l, &r, &b, &t); 668 STP_DEBUG(fprintf(stderr, "ijsgutenprint: l %d r %d t %d b %d pw %d ph %d\n", 669 l, r, t, b, pw, ph)); 670 if (l < 0) 671 l = 0; 672 if (r > pw) 673 r = pw; 674 if (t < 0) 675 t = 0; 676 if (b > ph) 677 b = ph; 678 } 679 else 680 stp_get_imageable_area(img->v, &l, &r, &b, &t); 681 STP_DEBUG(fprintf(stderr, "ijsgutenprint ppd_mode %d top left: %s\n", 682 ppd_mode, vbuf)); 683 STP_DEBUG(fprintf(stderr, "ijsgutenprint: l %d r %d t %d b %d pw %d ph %d\n", 684 l, r, t, b, pw, ph)); 685 code = gutenprint_parse_wxh(vbuf, strlen(vbuf), &w, &h); 686 if (code == 0) 687 { 688 int al = (w * 72) + .5; 689 int ah = (h * 72) + .5; 690 STP_DEBUG(fprintf(stderr, "ijsgutenprint: left top %f %f %d %d %s\n", 691 w * 72, h * 72, al, ah, vbuf)); 692 if (al >= 0) 693 stp_set_left(img->v, al); 694 if (ah >= 0) 695 stp_set_top(img->v, ah); 696 stp_set_width(img->v, r - l); 697 stp_set_height(img->v, b - t); 698 } 699 else 700 fprintf(stderr, "ERROR: ijsgutenprint: cannot parse TopLeft %s\n", vbuf); 701 } 702 else if (strcmp(key, "PaperSize") == 0) 703 { 704 double w, h; 705 code = gutenprint_parse_wxh(vbuf, strlen(vbuf), &w, &h); 706 if (code == 0) 707 { 708 const stp_papersize_t *p; 709 w *= 72; 710 h *= 72; 711 STP_DEBUG(fprintf(stderr, "ijsgutenprint: paper size %f %f %s\n", w, h, vbuf)); 712 stp_set_page_width(img->v, w); 713 stp_set_page_height(img->v, h); 714 if ((p = stp_get_papersize_by_size_exact(h, w)) != NULL) 715 { 716 STP_DEBUG(fprintf(stderr, "ijsgutenprint: Found page size %s\n", p->name)); 717 stp_set_string_parameter(img->v, "PageSize", p->name); 718 } 719 else 720 STP_DEBUG(fprintf(stderr, "ijsgutenprint: No matching paper size found\n")); 721 } 722 else 723 fprintf(stderr, "ERROR: ijsgutenprint: cannot parse PaperSize %s\n", vbuf); 724 } 725 726/* 727 * Duplex & Tumble. The PS: values come from the PostScript document, the 728 * others come from the command line. However, the PS: values seem to get 729 * fed back again as non PS: values after the command line is processed. 730 * The net effect is that the command line is always overridden by the 731 * values from the document. 732 */ 733 734 else if ((strcmp (key, "Duplex") == 0) || (strcmp (key, "PS:Duplex") == 0)) 735 { 736 stp_set_string_parameter(img->v, "x_Duplex", vbuf); 737 } 738 else if ((strcmp (key, "Tumble") == 0) || (strcmp (key, "PS:Tumble") == 0)) 739 { 740 stp_set_string_parameter(img->v, "x_Tumble", vbuf); 741 } 742 else if (strcmp(key, "STP_VERSION") == 0) 743 { 744 ppd_mode = 1; 745 if (strcmp(vbuf, version_id) != 0) 746 { 747 fprintf(stderr, VERSION_MISMATCH, 748 version_id, vbuf, version_id, vbuf); 749 version_is_ok = 0; 750 gutenprint_ppd_version = c_strdup(vbuf); 751 code = IJS_ERANGE; 752 } 753 } 754 else if (strncmp(key, "STP_OPT_REMAP_", strlen("STP_OPT_REMAP_")) == 0) 755 { 756 const char *xkey = key + strlen("STP_OPT_REMAP_"); 757 char *buf1 = stp_malloc(strlen("STP_OPT_") + strlen(xkey) + 1); 758 char *buf2 = c_strdup(vbuf); 759 strcpy(buf1, "STP_OPT_"); 760 strcpy(buf1 + strlen("STP_OPT_"), xkey); 761 stp_string_list_add_string(option_remap_list, buf1, buf2); 762 stp_free(buf1); 763 stp_free(buf2); 764 } 765 else if (strncmp(key, "STP_", 4) == 0) 766 { 767 stp_curve_t *curve; 768 stp_parameter_t desc; 769 const char *xkey = key + 4; 770 stp_param_string_t *pstr = stp_string_list_find(option_remap_list, key); 771 if (pstr) 772 { 773 xkey = pstr->text; 774 STP_DEBUG(fprintf(stderr, "ijsgutenprint: remapping %s to %s\n", 775 key, xkey)); 776 } 777 778 stp_describe_parameter(img->v, xkey, &desc); 779 switch (desc.p_type) 780 { 781 case STP_PARAMETER_TYPE_STRING_LIST: 782 stp_set_string_parameter(img->v, xkey, vbuf); 783 break; 784 case STP_PARAMETER_TYPE_FILE: 785 stp_set_file_parameter(img->v, xkey, vbuf); 786 break; 787 case STP_PARAMETER_TYPE_CURVE: 788 curve = stp_curve_create_from_string(vbuf); 789 if (curve) 790 { 791 stp_set_curve_parameter(img->v, xkey, curve); 792 stp_curve_destroy(curve); 793 } 794 else 795 fprintf(stderr, "ERROR: ijsgutenprint: cannot parse curve %s\n", vbuf); 796 break; 797 case STP_PARAMETER_TYPE_DOUBLE: 798 code = get_float(vbuf, xkey, &z); 799 if (code == 0) 800 stp_set_float_parameter(img->v, xkey, z); 801 else 802 fprintf(stderr, "ERROR: ijsgutenprint: cannot parse %s float %s\n", xkey, vbuf); 803 break; 804 case STP_PARAMETER_TYPE_INT: 805 code = get_int(vbuf, xkey, &i); 806 if (code == 0) 807 stp_set_int_parameter(img->v, xkey, i); 808 else 809 fprintf(stderr, "ERROR: ijsgutenprint: cannot parse %s int %s\n", xkey, vbuf); 810 break; 811 case STP_PARAMETER_TYPE_DIMENSION: 812 code = get_int(vbuf, xkey, &i); 813 if (code == 0) 814 stp_set_dimension_parameter(img->v, xkey, i); 815 else 816 fprintf(stderr, "ERROR: ijsgutenprint: cannot parse %s dimension %s\n", xkey, vbuf); 817 break; 818 case STP_PARAMETER_TYPE_BOOLEAN: 819 if (strcmp(vbuf, "False") == 0 || 820 strcmp(vbuf, "false") == 0 || 821 strcmp(vbuf, "FALSE") == 0 || 822 strcmp(vbuf, "0") == 0) 823 stp_set_boolean_parameter(img->v, xkey, 0); 824 else if (strcmp(vbuf, "True") == 0 || 825 strcmp(vbuf, "true") == 0 || 826 strcmp(vbuf, "TRUE") == 0 || 827 strcmp(vbuf, "1") == 0) 828 stp_set_boolean_parameter(img->v, xkey, 1); 829 else 830 fprintf(stderr, "ERROR: ijsgutenprint: cannot parse %s boolean %s\n", xkey, vbuf); 831 break; 832 default: 833 if (strncmp(xkey, "Enable", strlen("Enable")) == 0) 834 { 835 STP_DEBUG(fprintf(stderr, 836 "ijsgutenprint: Setting dummy enable parameter %s %s\n", 837 xkey, vbuf)); 838 stp_set_string_parameter(img->v, xkey, vbuf); 839 } 840 else 841 fprintf(stderr, "ERROR: ijsgutenprint: Bad parameter %s %d\n", key, desc.p_type); 842 } 843 stp_parameter_description_destroy(&desc); 844 } 845 846 if (code == 0) 847 { 848 GutenprintParamList *pl = gutenprint_find_key (img->params, key); 849 850 if (pl == NULL) 851 { 852 pl = (GutenprintParamList *)stp_malloc (sizeof (GutenprintParamList)); 853 pl->next = img->params; 854 pl->key = stp_malloc (strlen(key) + 1); 855 memcpy (pl->key, key, strlen(key) + 1); 856 img->params = pl; 857 } 858 else 859 { 860 stp_free (pl->value); 861 } 862 pl->value = stp_malloc (value_size); 863 memcpy (pl->value, value, value_size); 864 pl->value_size = value_size; 865 } 866 else 867 fprintf(stderr, "ERROR: ijsgutenprint: bad key code %d\n", code); 868 869 return code; 870} 871 872/**********************************************************/ 873 874static void 875gutenprint_errfunc(void *file, const char *buf, size_t bytes) 876{ 877 size_t next_nl = 0; 878 size_t where = 0; 879 FILE *prn = (FILE *)file; 880 while (where < bytes) 881 { 882 if (print_messages_as_errors) 883 fputs("ERROR: Gutenprint: ", prn); 884 else 885 fputs("DEBUG: Gutenprint internal: ", prn); 886 while (next_nl < bytes) 887 { 888 if (buf[next_nl++] == '\n') 889 break; 890 } 891 fwrite(buf + where, 1, next_nl - where, prn); 892 where = next_nl; 893 } 894} 895 896static void 897gutenprint_outfunc(void *data, const char *buffer, size_t bytes) 898{ 899 page_bytes_printed += bytes; 900 total_bytes_printed += bytes; 901 if ((data != NULL) && (buffer != NULL) && (bytes != 0)) 902 fwrite(buffer, 1, bytes, (FILE *)data); 903} 904 905/**********************************************************/ 906/* stp_image_t functions */ 907 908static int 909gutenprint_image_width(stp_image_t *image) 910{ 911 IMAGE *img = (IMAGE *)(image->rep); 912 STP_DEBUG(fprintf(stderr, "ijsgutenprint: image width %d\n", img->width)); 913 return img->width; 914} 915 916static int 917gutenprint_image_height(stp_image_t *image) 918{ 919 IMAGE *img = (IMAGE *)(image->rep); 920 STP_DEBUG(fprintf(stderr, "ijsgutenprint: image height %d (%d)\n", 921 img->height, img->height * img->xres / img->yres)); 922 return img->height * img->xres / img->yres; 923} 924 925static void 926throwaway_data(int amount, IMAGE *img) 927{ 928 char trash[4096]; /* Throwaway */ 929 int block_count = amount / 4096; 930 int leftover = amount % 4096; 931 while (block_count > 0) 932 { 933 ijs_server_get_data(img->ctx, trash, 4096); 934 block_count--; 935 } 936 if (leftover) 937 ijs_server_get_data(img->ctx, trash, leftover); 938} 939 940static int 941image_next_row(IMAGE *img) 942{ 943 int status = 0; 944 double n_bytes = img->bytes_left; 945 if (img->bytes_left) 946 { 947 948 if (n_bytes > img->row_width) 949 n_bytes = img->row_width; 950#ifdef VERBOSE 951 STP_DEBUG(fprintf(stderr, "ijsgutenprint: %.0f bytes left, reading %.d, on row %d\n", 952 img->bytes_left, (int) n_bytes, img->row)); 953#endif 954 throwaway_data(img->left_margin, img); 955 status = ijs_server_get_data(img->ctx, img->row_buf, (int) n_bytes); 956 if (status) 957 { 958 STP_DEBUG(fprintf(stderr, "ERROR: ijsgutenprint: page aborted (%d) at line %d!\n", 959 status, img->row)); 960 job_aborted = 1; 961 return status; 962 } 963 else 964 { 965 img->row++; 966 img->bytes_left -= (n_bytes + img->right_margin + img->left_margin); 967 } 968 throwaway_data(img->right_margin, img); 969 } 970 else 971 return 1; /* Done */ 972 return status; 973} 974 975static stp_image_status_t 976gutenprint_image_get_row(stp_image_t *image, unsigned char *data, size_t byte_limit, 977 int row) 978{ 979 IMAGE *img = (IMAGE *)(image->rep); 980 int physical_row = row * img->yres / img->xres; 981 982 if ((physical_row < 0) || (physical_row >= img->height)) 983 return STP_IMAGE_STATUS_ABORT; 984 985 /* Read until we reach the requested row. */ 986 while (physical_row > img->row) 987 { 988 if (image_next_row(img)) 989 return STP_IMAGE_STATUS_ABORT; 990 } 991 992 if (physical_row == img->row) 993 { 994 unsigned i, j, length; 995 switch (img->bps) 996 { 997 case 16: 998 case 8: 999 memcpy(data, img->row_buf, img->row_width); 1000 break; 1001 case 1: 1002 length = img->width / 8; 1003 for (i = 0; i < length; i++) 1004 for (j = 128; j > 0; j >>= 1) 1005 { 1006 if (img->row_buf[i] & j) 1007 data[0] = 255; 1008 else 1009 data[0] = 0; 1010 data++; 1011 } 1012 length = img->width % 8; 1013 for (j = 128; j > 1 << (7 - length); j >>= 1) 1014 { 1015 if (img->row_buf[i] & j) 1016 data[0] = 255; 1017 else 1018 data[0] = 0; 1019 data++; 1020 } 1021 break; 1022 default: 1023 return STP_IMAGE_STATUS_ABORT; 1024 } 1025 } 1026 else 1027 return STP_IMAGE_STATUS_ABORT; 1028 return STP_IMAGE_STATUS_OK; 1029} 1030 1031 1032static const char * 1033gutenprint_image_get_appname(stp_image_t *image) 1034{ 1035 return "ijsgutenprint"; 1036} 1037 1038/**********************************************************/ 1039 1040static const char * 1041safe_get_string_parameter(const stp_vars_t *v, const char *param) 1042{ 1043 const char *val = stp_get_string_parameter(v, param); 1044 if (val) 1045 return val; 1046 else 1047 return "NULL"; 1048} 1049 1050static void 1051stp_dbg(const char *msg, const stp_vars_t *v) 1052{ 1053 stp_parameter_list_t params = stp_get_parameter_list(v); 1054 int count = stp_parameter_list_count(params); 1055 int i; 1056 if (suppress_messages) 1057 return; 1058 fprintf(stderr, "DEBUG: %s\n", msg); 1059 fprintf(stderr, "DEBUG: ijsgutenprint: Settings: Model %s\n", stp_get_driver(v)); 1060 for (i = 0; i < count; i++) 1061 { 1062 const stp_parameter_t *p = stp_parameter_list_param(params, i); 1063 switch (p->p_type) 1064 { 1065 case STP_PARAMETER_TYPE_DOUBLE: 1066 if (stp_check_float_parameter(v, p->name, STP_PARAMETER_DEFAULTED)) 1067 fprintf(stderr, "DEBUG: ijsgutenprint: Settings: %s %f\n", 1068 p->name, stp_get_float_parameter(v, p->name)); 1069 break; 1070 case STP_PARAMETER_TYPE_INT: 1071 if (stp_check_int_parameter(v, p->name, STP_PARAMETER_DEFAULTED)) 1072 fprintf(stderr, "DEBUG: ijsgutenprint: Settings: %s %d\n", 1073 p->name, stp_get_int_parameter(v, p->name)); 1074 break; 1075 case STP_PARAMETER_TYPE_DIMENSION: 1076 if (stp_check_dimension_parameter(v, p->name, STP_PARAMETER_DEFAULTED)) 1077 fprintf(stderr, "DEBUG: ijsgutenprint: Settings: %s %d\n", 1078 p->name, stp_get_dimension_parameter(v, p->name)); 1079 break; 1080 case STP_PARAMETER_TYPE_BOOLEAN: 1081 if (stp_check_boolean_parameter(v, p->name, STP_PARAMETER_DEFAULTED)) 1082 fprintf(stderr, "DEBUG: ijsgutenprint: Settings: %s %s\n", 1083 p->name, 1084 stp_get_boolean_parameter(v, p->name) ? "true" : "false"); 1085 break; 1086 case STP_PARAMETER_TYPE_STRING_LIST: 1087 if (stp_check_string_parameter(v, p->name, STP_PARAMETER_DEFAULTED)) 1088 fprintf(stderr, "DEBUG: ijsgutenprint: Settings: %s %s\n", 1089 p->name, safe_get_string_parameter(v, p->name)); 1090 break; 1091 case STP_PARAMETER_TYPE_CURVE: 1092 if (stp_check_curve_parameter(v, p->name, STP_PARAMETER_DEFAULTED)) 1093 { 1094 char *curve = 1095 stp_curve_write_string(stp_get_curve_parameter(v, p->name)); 1096 fprintf(stderr, "DEBUG: ijsgutenprint: Settings: %s %s\n", 1097 p->name, curve); 1098 stp_free(curve); 1099 } 1100 break; 1101 default: 1102 break; 1103 } 1104 } 1105 stp_parameter_list_destroy(params); 1106} 1107 1108static void 1109purge_unused_float_parameters(stp_vars_t *v) 1110{ 1111 int i; 1112 stp_parameter_list_t params = stp_get_parameter_list(v); 1113 size_t count = stp_parameter_list_count(params); 1114 STP_DEBUG(fprintf(stderr, "ijsgutenprint: Purging unused floating point parameters\n")); 1115 for (i = 0; i < count; i++) 1116 { 1117 const stp_parameter_t *param = stp_parameter_list_param(params, i); 1118 if (param->p_type == STP_PARAMETER_TYPE_DOUBLE && 1119 !param->read_only && param->is_active && !param->is_mandatory) 1120 { 1121 size_t bytes = strlen(param->name) + strlen("Enable") + 1; 1122 char *tmp = stp_malloc(bytes); 1123 const char *value; 1124 sprintf(tmp, "Enable%s", param->name); 1125 STP_DEBUG(fprintf(stderr, "ijsgutenprint: Looking for parameter %s\n", tmp)); 1126 value = stp_get_string_parameter(v, tmp); 1127 if (value) 1128 { 1129 STP_DEBUG(fprintf(stderr, "ijsgutenprint: Found %s: %s\n", tmp, value)); 1130 if (strcmp(value, "Disabled") == 0) 1131 { 1132 STP_DEBUG(fprintf(stderr, "ijsgutenprint: Clearing %s\n", param->name)); 1133 stp_clear_float_parameter(v, param->name); 1134 } 1135 } 1136 stp_free(tmp); 1137 } 1138 if (param->p_type == STP_PARAMETER_TYPE_DIMENSION && 1139 !param->read_only && param->is_active && !param->is_mandatory) 1140 { 1141 size_t bytes = strlen(param->name) + strlen("Enable") + 1; 1142 char *tmp = stp_malloc(bytes); 1143 const char *value; 1144 sprintf(tmp, "Enable%s", param->name); 1145 STP_DEBUG(fprintf(stderr, "ijsgutenprint: Looking for parameter %s\n", tmp)); 1146 value = stp_get_string_parameter(v, tmp); 1147 if (value) 1148 { 1149 STP_DEBUG(fprintf(stderr, "ijsgutenprint: Found %s: %s\n", tmp, value)); 1150 if (strcmp(value, "Disabled") == 0) 1151 { 1152 STP_DEBUG(fprintf(stderr, "ijsgutenprint: Clearing %s\n", param->name)); 1153 stp_clear_dimension_parameter(v, param->name); 1154 } 1155 } 1156 stp_free(tmp); 1157 } 1158 } 1159 stp_parameter_list_destroy(params); 1160} 1161 1162static void 1163validate_options(stp_image_t *image) 1164{ 1165 IMAGE *im = (IMAGE *) (image->rep); 1166 stp_vars_t *v = im->v; 1167 stp_parameter_list_t params = stp_get_parameter_list(v); 1168 int nparams = stp_parameter_list_count(params); 1169 int i; 1170 for (i = 0; i < nparams; i++) 1171 { 1172 const stp_parameter_t *param = stp_parameter_list_param(params, i); 1173 stp_parameter_t desc; 1174 stp_describe_parameter(v, param->name, &desc); 1175 if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST) 1176 { 1177 if (!stp_string_list_is_present 1178 (desc.bounds.str, stp_get_string_parameter(v, desc.name))) 1179 { 1180 STP_DEBUG(fprintf(stderr, "ijsgutenprint: clearing string %s (%s)\n", 1181 desc.name, safe_get_string_parameter(v, desc.name))); 1182 stp_clear_string_parameter(v, desc.name); 1183 if (!desc.read_only && desc.is_mandatory && desc.is_active) 1184 { 1185 STP_DEBUG(fprintf(stderr, "ijsgutenprint: setting default string %s to %s\n", 1186 desc.name, desc.deflt.str ? desc.deflt.str : "(null)")); 1187 stp_set_string_parameter(v, desc.name, desc.deflt.str); 1188 if (strcmp(desc.name, "PageSize") == 0) 1189 { 1190 const stp_papersize_t *ps = 1191 stp_get_papersize_by_name(desc.deflt.str); 1192 if (ps->width > 0) 1193 { 1194 STP_DEBUG(fprintf(stderr, "ijsgutenprint: setting page width to %d\n", 1195 ps->width)); 1196 if (ps->width < stp_get_page_width(v)) 1197 stp_set_page_width(v, ps->width); 1198 if (ps->width < stp_get_left(v) + stp_get_width(v)) 1199 { 1200#if 0 1201 if (im->width < ps->width) 1202 im->width = ps->width; 1203#endif 1204 STP_DEBUG(fprintf(stderr, "ijsgutenprint: setting width to %d\n", 1205 ps->width - stp_get_left(v))); 1206 stp_set_width(v, ps->width - stp_get_left(v)); 1207 } 1208 } 1209 if (ps->height > 0) 1210 { 1211 STP_DEBUG(fprintf(stderr, "ijsgutenprint: setting page height to %d\n", 1212 ps->height)); 1213 if (ps->height < stp_get_page_height(v)) 1214 stp_set_page_height(v, ps->height); 1215 if (ps->height < stp_get_top(v) + stp_get_height(v)) 1216 { 1217#if 0 1218 if (im->height < ps->height) 1219 im->height = ps->height; 1220#endif 1221 STP_DEBUG(fprintf(stderr, "ijsgutenprint: setting height to %d\n", 1222 ps->height - stp_get_top(v))); 1223 stp_set_height(v, ps->height - stp_get_top(v)); 1224 } 1225 } 1226 } 1227 } 1228 } 1229 } 1230 stp_parameter_description_destroy(&desc); 1231 } 1232 stp_parameter_list_destroy(params); 1233} 1234 1235 1236 1237int 1238main (int argc, char **argv) 1239{ 1240 IjsPageHeader ph; 1241 int status; 1242 int page = 0; 1243 IMAGE img; 1244 stp_image_t si; 1245 const stp_printer_t *printer = NULL; 1246 FILE *f = NULL; 1247 int l, t, r, b, w, h; 1248 int width, height; 1249 1250 if (getenv("STP_SUPPRESS_MESSAGES")) 1251 suppress_messages = 1; 1252 1253 if (getenv("STP_DEBUG_STARTUP")) 1254 while (SDEBUG) 1255 ; 1256 1257 memset(&img, 0, sizeof(img)); 1258 1259 stp_init(); 1260 version_id = stp_get_version(); 1261 option_remap_list = stp_string_list_create(); 1262 1263 img.ctx = ijs_server_init(); 1264 if (img.ctx == NULL) 1265 return 1; 1266 1267 img.v = stp_vars_create(); 1268 if (img.v == NULL) 1269 { 1270 ijs_server_done(img.ctx); 1271 return 1; 1272 } 1273 stp_set_top(img.v, 0); 1274 stp_set_left(img.v, 0); 1275 1276 /* Error messages to stderr. */ 1277 stp_set_errfunc(img.v, gutenprint_errfunc); 1278 stp_set_errdata(img.v, stderr); 1279 1280 /* Printer data goes to file f, but we haven't opened it yet. */ 1281 stp_set_outfunc(img.v, gutenprint_outfunc); 1282 stp_set_outdata(img.v, NULL); 1283 1284 memset(&si, 0, sizeof(si)); 1285 si.width = gutenprint_image_width; 1286 si.height = gutenprint_image_height; 1287 si.get_row = gutenprint_image_get_row; 1288 si.get_appname = gutenprint_image_get_appname; 1289 si.rep = &img; 1290 1291 ijs_server_install_status_cb (img.ctx, gutenprint_status_cb, &img); 1292 ijs_server_install_list_cb (img.ctx, gutenprint_list_cb, &img); 1293 ijs_server_install_enum_cb (img.ctx, gutenprint_enum_cb, &img); 1294 ijs_server_install_get_cb (img.ctx, gutenprint_get_cb, &img); 1295 ijs_server_install_set_cb(img.ctx, gutenprint_set_cb, &img); 1296 1297 stp_dbg("ijsgutenprint: about to start\n", img.v); 1298 1299 STP_DEBUG(fprintf(stderr, "ijsgutenprint: About to get page header\n")); 1300 status = ijs_server_get_page_header(img.ctx, &ph); 1301 while (status == 0) 1302 { 1303 stp_vars_t *old_v = NULL; 1304 STP_DEBUG(fprintf(stderr, "ijsgutenprint: got page header, %d x %d\n", 1305 ph.width, ph.height)); 1306 stp_dbg("ijsgutenprint: have page header\n", img.v); 1307 1308 status = image_init(&img, &ph); 1309 if (status) 1310 { 1311 fprintf(stderr, "ERROR: ijsgutenprint: image_init failed %d\n", status); 1312 break; 1313 } 1314 1315 if (page == 0) 1316 { 1317 if (img.fd) 1318 { 1319 f = fdopen(img.fd - 1, "wb"); 1320 if (!f) 1321 { 1322 fprintf(stderr, "ERROR: ijsgutenprint: Unable to open file descriptor: %s\n", 1323 strerror(errno)); 1324 status = -1; 1325 break; 1326 } 1327 } 1328 else if (img.filename && strlen(img.filename) > 0) 1329 { 1330 f = fopen(img.filename, "wb"); 1331 if (!f) 1332 { 1333 status = -1; 1334 fprintf(stderr, "ERROR: ijsgutenprint: Unable to open %s: %s\n", img.filename, 1335 strerror(errno)); 1336 break; 1337 } 1338 } 1339 1340 /* Printer data to file */ 1341 stp_set_outdata(img.v, f); 1342 } 1343 1344 printer = stp_get_printer(img.v); 1345 if (printer == NULL) 1346 { 1347 fprintf(stderr, "ERROR: ijsgutenprint: Unknown printer %s\n", 1348 stp_get_driver(img.v)); 1349 status = -1; 1350 break; 1351 } 1352 purge_unused_float_parameters(img.v); 1353 stp_merge_printvars(img.v, stp_printer_get_defaults(printer)); 1354 1355 1356 img.total_bytes = (double) ((ph.n_chan * ph.bps * ph.width + 7) >> 3) 1357 * (double) ph.height; 1358 img.bytes_left = img.total_bytes; 1359 1360 stp_set_float_parameter(img.v, "AppGamma", 1.0); 1361 stp_get_media_size(img.v, &w, &h); 1362 stp_get_imageable_area(img.v, &l, &r, &b, &t); 1363 STP_DEBUG(fprintf(stderr, "ijsgutenprint: chan %d bps %d image w %d %d h %d %d\n", 1364 ph.n_chan, ph.bps, stp_get_width(img.v), img.width, 1365 stp_get_height(img.v), img.height)); 1366 if (ppd_mode) 1367 { 1368 int lt, rt, bt, tt; 1369 1370 stp_get_maximum_imageable_area(img.v, <, &rt, &bt, &tt); 1371 STP_DEBUG(fprintf(stderr, "ijsgutenprint: w %d h %d l %d %d t %d %d r %d %d b %d %d\n", 1372 w, h, l, lt, t, tt, r, rt, b, bt)); 1373 if (lt < 0) 1374 lt = 0; 1375 if (tt < 0) 1376 tt = 0; 1377 if (rt > w) 1378 rt = w; 1379 if (bt > h) 1380 bt = h; 1381 if (l < 0) 1382 l = 0; 1383 if (t < 0) 1384 t = 0; 1385 if (r > w + l) 1386 r = w + l; 1387 if (b > h + t) 1388 b = h + t; 1389 STP_DEBUG(fprintf(stderr, "ijsgutenprint: w %d h %d l %d %d t %d %d r %d %d b %d %d\n", 1390 w, h, l, lt, t, tt, r, rt, b, bt)); 1391 if (lt < l) 1392 { 1393 STP_DEBUG(fprintf(stderr, "ijsgutenprint: l %d, lt %d\n", l, lt)); 1394 img.left_margin = (l - lt) * ph.xres * ph.n_chan * ph.bps / 8 / 72; 1395 img.width -= (l - lt) * ph.xres / 72; 1396 STP_DEBUG(fprintf(stderr, "ijsgutenprint: chan %d bps %d image w %d %d h %d %d\n", 1397 ph.n_chan, ph.bps, stp_get_width(img.v), img.width, 1398 stp_get_height(img.v), img.height)); 1399 } 1400 else 1401 img.left_margin = 0; 1402 stp_set_left(img.v, l); 1403 if (tt < t) 1404 { 1405 STP_DEBUG(fprintf(stderr, "ijsgutenprint: t %d, tt %d\n", t, tt)); 1406 img.top_margin = (t - tt) * ph.yres * ph.n_chan * ph.bps / 8 / 72; 1407 img.height -= (t - tt) * ph.yres / 72; 1408 STP_DEBUG(fprintf(stderr, "ijsgutenprint: chan %d bps %d image w %d %d h %d %d\n", 1409 ph.n_chan, ph.bps, stp_get_width(img.v), img.width, 1410 stp_get_height(img.v), img.height)); 1411 } 1412 else 1413 img.top_margin = 0; 1414 stp_set_top(img.v, t); 1415 if (rt > r) 1416 { 1417 STP_DEBUG(fprintf(stderr, "ijsgutenprint: r %d, rt %d\n", r, rt)); 1418 img.right_margin = (rt - r) * ph.xres * ph.n_chan * ph.bps / 8 / 72; 1419 img.width -= (rt - r) * ph.xres / 72; 1420 STP_DEBUG(fprintf(stderr, "ijsgutenprint: chan %d bps %d image w %d %d h %d %d\n", 1421 ph.n_chan, ph.bps, stp_get_width(img.v), img.width, 1422 stp_get_height(img.v), img.height)); 1423 } 1424 else 1425 img.right_margin = 0; 1426 if (bt > b) 1427 { 1428 STP_DEBUG(fprintf(stderr, "ijsgutenprint: b %d, bt %d\n", b, bt)); 1429 img.bottom_margin = (bt - b) * ph.yres * ph.n_chan * ph.bps / 8 / 72; 1430 img.height -= (bt - b) * ph.yres / 72; 1431 STP_DEBUG(fprintf(stderr, "ijsgutenprint: chan %d bps %d image w %d %d h %d %d\n", 1432 ph.n_chan, ph.bps, stp_get_width(img.v), img.width, 1433 stp_get_height(img.v), img.height)); 1434 } 1435 else 1436 img.bottom_margin = 0; 1437 } 1438 if (l < 0) 1439 width = r; 1440 else 1441 width = r - l; 1442 stp_set_width(img.v, width); 1443 if (t < 0) 1444 height = b; 1445 else 1446 height = b - t; 1447 img.row_width -= img.left_margin; 1448 img.row_width -= img.right_margin; 1449 stp_set_height(img.v, height); 1450 stp_set_int_parameter(img.v, "PageNumber", page); 1451 STP_DEBUG(fprintf(stderr, "ijsgutenprint: w %d h %d l %d r %d t %d b %d\n", 1452 width, height, l, r, t, b)); 1453 STP_DEBUG(fprintf(stderr, "ijsgutenprint: chan %d bps %d image w %d %d h %d %d\n", 1454 ph.n_chan, ph.bps, stp_get_width(img.v), img.width, 1455 stp_get_height(img.v), img.height)); 1456 STP_DEBUG(fprintf(stderr, "ijsgutenprint: margins l %d r %d t %d b %d row width %d\n", 1457 img.left_margin, img.right_margin, 1458 img.top_margin, img.bottom_margin, 1459 img.row_width)); 1460 1461/* 1462 * Fix up the duplex/tumble settings stored in the "x_" parameters 1463 * If Duplex is "true" then look at "Tumble". If duplex is not "true" or "false" 1464 * then just take it (e.g. Duplex=DuplexNoTumble). 1465 */ 1466 STP_DEBUG(fprintf(stderr, "ijsgutenprint: x_Duplex=%s\n", safe_get_string_parameter(img.v, "x_Duplex"))); 1467 STP_DEBUG(fprintf(stderr, "ijsgutenprint: x_Tumble=%s\n", safe_get_string_parameter(img.v, "x_Tumble"))); 1468 1469 if (stp_get_string_parameter(img.v, "x_Duplex")) 1470 { 1471 if (strcmp(stp_get_string_parameter(img.v, "x_Duplex"), "false") == 0) 1472 stp_set_string_parameter(img.v, "Duplex", "None"); 1473 else if (strcmp(stp_get_string_parameter(img.v, "x_Duplex"), "true") == 0) 1474 { 1475 if (stp_get_string_parameter(img.v, "x_Tumble")) 1476 { 1477 if (strcmp(stp_get_string_parameter(img.v, "x_Tumble"), "false") == 0) 1478 stp_set_string_parameter(img.v, "Duplex", "DuplexNoTumble"); 1479 else 1480 stp_set_string_parameter(img.v, "Duplex", "DuplexTumble"); 1481 } 1482 else /* Tumble missing, assume false */ 1483 stp_set_string_parameter(img.v, "Duplex", "DuplexNoTumble"); 1484 } 1485 else /* Not true or false */ 1486 stp_set_string_parameter(img.v, "Duplex", stp_get_string_parameter(img.v, "x_Duplex")); 1487 } 1488 1489/* can I destroy the unused parameters? */ 1490 1491 STP_DEBUG(fprintf(stderr, "ijsgutenprint: Duplex=%s\n", safe_get_string_parameter(img.v, "Duplex"))); 1492 1493 validate_options(&si); 1494 stp_dbg("ijsgutenprint: about to print", img.v); 1495 STP_DEBUG(fprintf(stderr, "ijsgutenprint: w %d h %d l %d t %d\n", 1496 stp_get_width(img.v), stp_get_height(img.v), 1497 stp_get_left(img.v), stp_get_top(img.v))); 1498 STP_DEBUG(fprintf(stderr, "ijsgutenprint: start printing page %d\n", page)); 1499 print_messages_as_errors = 1; 1500 if (!version_is_ok) 1501 { 1502 fprintf(stderr, VERSION_MISMATCH, version_id, 1503 gutenprint_ppd_version, version_id, gutenprint_ppd_version); 1504 status = IJS_ERANGE; 1505 break; 1506 } 1507 else if (stp_verify(img.v)) 1508 { 1509 page_bytes_printed = 0; 1510 if (page == 0) 1511 stp_start_job(img.v, &si); 1512 stp_print(img.v, &si); 1513 STP_DEBUG(fprintf(stderr, "ijsgutenprint: printed page %d, %.0f bytes\n", 1514 page, page_bytes_printed)); 1515 old_v = stp_vars_create_copy(img.v); 1516 } 1517 else 1518 { 1519 fprintf(stderr, "ERROR: ijsgutenprint: Bad parameters; cannot continue!\n"); 1520 status = IJS_ERANGE; 1521 break; 1522 } 1523 if (job_aborted) 1524 { 1525 STP_DEBUG(fprintf(stderr, "ijsgutenprint: aborting job\n")); 1526 status = 1; 1527 } 1528 else 1529 { 1530 STP_DEBUG(fprintf(stderr, "ijsgutenprint: done printing page %d\n", page)); 1531 1532 while (img.bytes_left) 1533 { 1534 status = image_next_row(&img); 1535 if (status) 1536 { 1537 fprintf(stderr, "ERROR: ijsgutenprint: Get next row failed at %.0f\n", 1538 img.bytes_left); 1539 break; 1540 } 1541 } 1542 1543 image_finish(&img); 1544 status = ijs_server_get_page_header(img.ctx, &ph); 1545 } 1546 if (status > 0) 1547 { 1548 fprintf(stderr, "INFO: ijsgutenprint Ready to print.\n"); 1549 stp_end_job(old_v, &si); 1550 } 1551 else 1552 { 1553 stp_vars_destroy(old_v); 1554 page++; 1555 } 1556 } 1557 if (f) 1558 { 1559 fclose(f); 1560 } 1561 1562 if (status > 0) 1563 status = 0; /* normal exit */ 1564 1565 ijs_server_done(img.ctx); 1566 1567 STP_DEBUG(fprintf (stderr, "ijsgutenprint: printed total %.0f bytes\n", 1568 total_bytes_printed)); 1569 STP_DEBUG(fprintf (stderr, "ijsgutenprint: server exiting with status %d\n", status)); 1570 return status; 1571} 1572