=== modified file 'filter/pdftops.c' --- filter/pdftops.c 2012-04-11 19:08:01 +0000 +++ filter/pdftops.c 2012-05-16 07:29:29 +0000 @@ -37,6 +37,13 @@ #define MAX_CHECK_COMMENT_LINES 20 /* + * Type definitions + */ + +typedef unsigned renderer_t; +enum renderer_e {GS = 0, PDFTOPS = 1}; + +/* * Local functions... */ @@ -49,7 +56,7 @@ static int job_canceled = 0; int pdftopdfapplied = 0; -char *deviceCopies = "1"; +char deviceCopies[32] = "1"; int deviceCollate = 0; @@ -129,7 +136,11 @@ p = strchr(buf+19,':') + 1; while (*p == ' ' || *p == '\t') p++; - deviceCopies = strdup(p); + strncpy(deviceCopies, p, sizeof(deviceCopies)); + deviceCopies[sizeof(deviceCopies) - 1] = '\0'; + p = deviceCopies + strlen(deviceCopies) - 1; + while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') p--; + *(p + 1) = '\0'; pdftopdfapplied = 1; } else if (strncmp(buf,"%%PDFTOPDFCollate",17) == 0) { char *p; @@ -202,6 +213,7 @@ main(int argc, /* I - Number of command-line args */ char *argv[]) /* I - Command-line arguments */ { + renderer_t renderer = CUPS_PDFTOPS_RENDERER; /* Renderer: gs or pdftops */ int fd; /* Copy file descriptor */ char *filename, /* PDF file to convert */ tempfile[1024]; /* Temporary file */ @@ -216,6 +228,8 @@ ppd_size_t *size; /* Current page size */ char resolution[128] = "300";/* Output resolution */ int xres = 0, yres = 0, /* resolution values */ + maxres = CUPS_PDFTOPS_MAX_RESOLUTION, + /* Maximum image rendering resolution */ numvalues; /* Number of values actually read */ ppd_choice_t *choice; ppd_attr_t *attr; @@ -304,7 +318,7 @@ tempfile); while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) - write(fd, buffer, bytes); + bytes = write(fd, buffer, bytes); close(fd); @@ -337,6 +351,21 @@ cupsMarkOptions(ppd, num_options, options); /* + * Select the PDF renderer: Ghostscript (gs) or Poppler (pdftops) + */ + + if ((val = cupsGetOption("pdftops-renderer", num_options, options)) != NULL) + { + if (strcasecmp(val, "gs") == 0) + renderer = GS; + else if (strcasecmp(val, "pdftops") == 0) + renderer = PDFTOPS; + else + fprintf(stderr, + "WARNING: Invalid value for \"pdftops-renderer\": \"%s\"\n", val); + } + + /* * Build the pstops command-line... */ @@ -362,7 +391,7 @@ * printer does hardware collate. */ - pstops_options = realloc(pstops_options, sizeof(pstops_options) + 8); + pstops_options = realloc(pstops_options, strlen(pstops_options) + 9); pstops_end = pstops_options + strlen(pstops_options); strcpy(pstops_end, " Collate"); } @@ -382,10 +411,13 @@ * Build the command-line for the pdftops or gs filter... */ -#ifdef HAVE_PDFTOPS + if (renderer == PDFTOPS) + { pdf_argv[0] = (char *)"pdftops"; pdf_argc = 1; -#else + } + else + { pdf_argv[0] = (char *)"gs"; pdf_argv[1] = (char *)"-q"; pdf_argv[2] = (char *)"-dNOPAUSE"; @@ -398,7 +430,7 @@ # endif /* HAVE_GHOSTSCRIPT_PS2WRITE */ pdf_argv[6] = (char *)"-sOUTPUTFILE=%stdout"; pdf_argc = 7; -#endif /* HAVE_PDFTOPS */ + } if (ppd) { @@ -408,31 +440,34 @@ if (ppd->language_level == 1) { -#ifdef HAVE_PDFTOPS + if (renderer == PDFTOPS) + { pdf_argv[pdf_argc++] = (char *)"-level1"; pdf_argv[pdf_argc++] = (char *)"-noembtt"; -#else + } + else pdf_argv[pdf_argc++] = (char *)"-dLanguageLevel=1"; -#endif /* HAVE_PDFTOPS */ } else if (ppd->language_level == 2) { -#ifdef HAVE_PDFTOPS + if (renderer == PDFTOPS) + { pdf_argv[pdf_argc++] = (char *)"-level2"; if (!ppd->ttrasterizer) pdf_argv[pdf_argc++] = (char *)"-noembtt"; -#else + } + else pdf_argv[pdf_argc++] = (char *)"-dLanguageLevel=2"; -#endif /* HAVE_PDFTOPS */ } else -#ifdef HAVE_PDFTOPS + { + if (renderer == PDFTOPS) /* Do not emit PS Level 3 with Poppler, some HP PostScript printers do not like it. See https://bugs.launchpad.net/bugs/277404. */ pdf_argv[pdf_argc++] = (char *)"-level2"; -#else + else pdf_argv[pdf_argc++] = (char *)"-dLanguageLevel=3"; -#endif /* HAVE_PDFTOPS */ + } if ((val = cupsGetOption("fitplot", num_options, options)) == NULL) val = cupsGetOption("fit-to-page", num_options, options); @@ -479,7 +514,8 @@ orientation ^= 1; } -#ifdef HAVE_PDFTOPS + if (renderer == PDFTOPS) + { if (orientation & 1) { snprintf(pdf_width, sizeof(pdf_width), "%.0f", size->length); @@ -497,7 +533,9 @@ pdf_argv[pdf_argc++] = pdf_height; pdf_argv[pdf_argc++] = (char *)"-expand"; -#else + } + else + { if (orientation & 1) { snprintf(pdf_width, sizeof(pdf_width), "-dDEVICEWIDTHPOINTS=%.0f", @@ -515,10 +553,10 @@ pdf_argv[pdf_argc++] = pdf_width; pdf_argv[pdf_argc++] = pdf_height; -#endif /* HAVE_PDFTOPS */ } -#if defined(HAVE_PDFTOPS) && defined(HAVE_PDFTOPS_WITH_ORIGPAGESIZES) - else + } +#ifdef HAVE_POPPLER_PDFTOPS_WITH_ORIGPAGESIZES + else if (renderer == PDFTOPS) { /* * Use the page sizes of the original PDF document, this way documents @@ -527,23 +565,29 @@ pdf_argv[pdf_argc++] = (char *)"-origpagesizes"; } -#endif /* HAVE_PDFTOPS && HAVE_PDFTOPS_WITH_ORIGPAGESIZES */ +#endif /* HAVE_POPPLER_PDFTOPS_WITH_ORIGPAGESIZES */ /* * Set output resolution ... */ - if ((choice = ppdFindMarkedChoice(ppd, "Resolution")) != NULL) - strncpy(resolution, choice->choice, sizeof(resolution)); - else if ((attr = ppdFindAttr(ppd,"DefaultResolution",NULL)) != NULL) - strncpy(resolution, attr->value, sizeof(resolution)); - else if (cupsRasterInterpretPPD(&header, ppd, num_options, options, NULL) == 0) + /* Ignore error exits of cupsRasterInterpretPPD(), if it found a resolution + setting before erroring it is OK for us */ + cupsRasterInterpretPPD(&header, ppd, num_options, options, NULL); + /* 100 dpi is default, this means that if we have 100 dpi here this + method failed to find the printing resolution */ + if (header.HWResolution[0] > 100 && header.HWResolution[1] > 100) { xres = header.HWResolution[0]; yres = header.HWResolution[1]; } + else if ((choice = ppdFindMarkedChoice(ppd, "Resolution")) != NULL) + strncpy(resolution, choice->choice, sizeof(resolution)); + else if ((attr = ppdFindAttr(ppd,"DefaultResolution",NULL)) != NULL) + strncpy(resolution, attr->value, sizeof(resolution)); } + resolution[sizeof(resolution)-1] = '\0'; if ((xres > 0) || (yres > 0) || ((numvalues = sscanf(resolution, "%dx%d", &xres, &yres)) > 0)) { @@ -553,39 +597,49 @@ xres = 300; /* - * Reduce the image rendering resolution to make processing of jobs by poth - * the PDF->PS converter and the printer faster + * Get the ceiling for the image rendering resolution */ - /* - if (xres % 90 == 0) - { - if (xres > 360) - xres = max(360, xres / 2); - } - else if (xres % 75 == 0) + + if ((val = cupsGetOption("pdftops-max-image-resolution", num_options, options)) != NULL) { - if (xres > 300) - xres = max(300, xres / 2); + if ((numvalues = sscanf(val, "%d", &yres)) > 0) + maxres = yres; + else + fprintf(stderr, + "WARNING: Invalid value for \"pdftops-max-image-resolution\": \"%s\"\n", val); } + + /* + * Reduce the image rendering resolution to not exceed a given maximum + * to make processing of jobs by the PDF->PS converter and the printer faster + * + * maxres = 0 means no limit */ -#ifdef HAVE_PDFTOPS -#ifdef HAVE_PDFTOPS_WITH_RESOLUTION + if (maxres) + while (xres > maxres) + xres = xres / 2; + + if (renderer == PDFTOPS) + { +#ifdef HAVE_POPPLER_PDFTOPS_WITH_RESOLUTION /* - * Set resolution to avoid slow processing by the printer when the resolution - * of embedded images does not match the printer' s resolution + * Set resolution to avoid slow processing by the printer when the + * resolution of embedded images does not match the printer's resolution */ pdf_argv[pdf_argc++] = (char *)"-r"; snprintf(resolution, sizeof(resolution), "%d", xres); pdf_argv[pdf_argc++] = resolution; fprintf(stderr, "DEBUG: Using image rendering resolution %d dpi\n", xres); -#endif /* HAVE_PDFTOPS_WITH_RESOLUTION */ +#endif /* HAVE_POPPLER_PDFTOPS_WITH_RESOLUTION */ pdf_argv[pdf_argc++] = filename; pdf_argv[pdf_argc++] = (char *)"-"; -#else + } + else + { /* - * Set resolution to avoid slow processing by the printer when the resolution - * of embedded images does not match the printer' s resolution + * Set resolution to avoid slow processing by the printer when the + * resolution of embedded images does not match the printer's resolution */ snprintf(resolution, 127, "-r%d", xres); pdf_argv[pdf_argc++] = resolution; @@ -626,7 +680,7 @@ pdf_argv[pdf_argc++] = (char *)"save pop"; pdf_argv[pdf_argc++] = (char *)"-f"; pdf_argv[pdf_argc++] = filename; -#endif /* HAVE_PDFTOPS */ + } pdf_argv[pdf_argc] = NULL; @@ -635,14 +689,13 @@ * of the printer's PostScript interpreter? */ -#ifdef HAVE_PDFTOPS + if (renderer == PDFTOPS) need_post_proc = 0; -#else + else need_post_proc = (ppd && ppd->manufacturer && (!strncasecmp(ppd->manufacturer, "Kyocera", 7) || !strncasecmp(ppd->manufacturer, "Brother", 7)) ? 1 : 0); -#endif /* HAVE_PDFTOPS */ /* * Execute "pdftops/gs | pstops [ | post-processing ]"... @@ -684,13 +737,16 @@ close(pstops_pipe[0]); close(pstops_pipe[1]); -#ifdef HAVE_PDFTOPS - execv(CUPS_PDFTOPS, pdf_argv); + if (renderer == PDFTOPS) + { + execv(CUPS_POPPLER_PDFTOPS, pdf_argv); perror("DEBUG: Unable to execute pdftops program"); -#else + } + else + { execv(CUPS_GHOSTSCRIPT, pdf_argv); perror("DEBUG: Unable to execute gs program"); -#endif /* HAVE_PDFTOPS */ + } exit(1); } @@ -700,11 +756,10 @@ * Unable to fork! */ -#ifdef HAVE_PDFTOPS + if (renderer == PDFTOPS) perror("DEBUG: Unable to execute pdftops program"); -#else + else perror("DEBUG: Unable to execute gs program"); -#endif /* HAVE_PDFTOPS */ exit_status = 1; goto error; @@ -754,9 +809,7 @@ else printf("%s", buffer); -#ifndef HAVE_PDFTOPS - - if (ppd && ppd->manufacturer) + if (renderer == GS && ppd && ppd->manufacturer) { /* @@ -805,8 +858,6 @@ } } -#endif /* !HAVE_PDFTOPS */ - if (strncmp(buffer, "%%BeginProlog", 13)) { /* Close newly created Prolog section */ @@ -924,11 +975,7 @@ fprintf(stderr, "DEBUG: PID %d (%s) stopped with status %d!\n", wait_pid, -#ifdef HAVE_PDFTOPS - wait_pid == pdf_pid ? "pdftops" : -#else - wait_pid == pdf_pid ? "gs" : -#endif /* HAVE_PDFTOPS */ + wait_pid == pdf_pid ? (renderer == PDFTOPS ? "pdftops" : "gs") : (wait_pid == pstops_pid ? "pstops" : "Post-processing"), exit_status); } @@ -937,11 +984,7 @@ fprintf(stderr, "DEBUG: PID %d (%s) was terminated normally with signal %d!\n", wait_pid, -#ifdef HAVE_PDFTOPS - wait_pid == pdf_pid ? "pdftops" : -#else - wait_pid == pdf_pid ? "gs" : -#endif /* HAVE_PDFTOPS */ + wait_pid == pdf_pid ? (renderer == PDFTOPS ? "pdftops" : "gs") : (wait_pid == pstops_pid ? "pstops" : "Post-processing"), exit_status); } @@ -950,11 +993,7 @@ exit_status = WTERMSIG(wait_status); fprintf(stderr, "DEBUG: PID %d (%s) crashed on signal %d!\n", wait_pid, -#ifdef HAVE_PDFTOPS - wait_pid == pdf_pid ? "pdftops" : -#else - wait_pid == pdf_pid ? "gs" : -#endif /* HAVE_PDFTOPS */ + wait_pid == pdf_pid ? (renderer == PDFTOPS ? "pdftops" : "gs") : (wait_pid == pstops_pid ? "pstops" : "Post-processing"), exit_status); } @@ -962,11 +1001,7 @@ else { fprintf(stderr, "DEBUG: PID %d (%s) exited with no errors.\n", wait_pid, -#ifdef HAVE_PDFTOPS - wait_pid == pdf_pid ? "pdftops" : -#else - wait_pid == pdf_pid ? "gs" : -#endif /* HAVE_PDFTOPS */ + wait_pid == pdf_pid ? (renderer == PDFTOPS ? "pdftops" : "gs") : (wait_pid == pstops_pid ? "pstops" : "Post-processing")); } }