]> git.ipfire.org Git - thirdparty/cups-filters.git/commitdiff
libcupsfilters: Make cupsRasterParseIPPOptions() work correctly with PPDs
authorTill Kamppeter <till.kamppeter@gmail.com>
Tue, 12 Oct 2021 11:33:26 +0000 (13:33 +0200)
committerTill Kamppeter <till.kamppeter@gmail.com>
Wed, 12 Jan 2022 23:29:36 +0000 (20:29 -0300)
cupsRasterParseIPPOptions() interprets job options/IPP attributes and
their settings just bei their names. This works well when the
destination printer is not described by a PPD file.

If there is a PPD file, their can be weird option and choice names
which do not tell what they are good for, giving wrong
impressions. Only the PostScript or PJL code assigned to the choices
in the PPD file tells what they actually are supposed to do.

A good example for that is the "Resolution" option of Gutenprint. As
the developers of Gutenprint do not want to solely and directly set
the print resolution with this option (as was Adobe's idea for it),
and instead, do more things with it, as having an "Automatic" choice
or variants of the same resolution (for example different dithering
algorithms), but PPD standards require the choices to be "XXXxYYYdpi"
without exceptions, they come with names like "601x600dpi" for the
variants and the PPD's embedded PostScript code contains the actual
resolution.

To avoid that cupsRasterParseIPPOptions() mis-interprets such weird
PPD options, we check whether we are using a PPD (via the PPD
environment variable) and if so we refrain from parsing options which
are in the PPD. Only if set_defaults = 1 is set, we use them but via a
call of callRasterInterpretPPD() instead of interpreting them by
ourselves option/choice-name-only.

(cherry picked from commit d77db8903a635fa13f4e043fa05b49b5f40593b6)

cupsfilters/raster.c

index c9da09acdba71c8beee6e112f901c6ee345c43c5..293eb8d05da0eae247fb0c83ff2f253e2315db53 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <config.h>
 #include <cups/cups.h>
+#include <cups/ppd.h>
 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
 #define HAVE_CUPS_1_7 1
 #endif
@@ -87,6 +88,10 @@ cupsRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
                 *media_type;           /* Media type */
   pwg_media_t   *size_found;            /* page size found for given name */
   float         size;                   /* page size dimension */
+  int           num_non_ppd_options = 0;/* Number of options which are not
+                                           in the PPD */
+  cups_option_t *non_ppd_options = NULL;/* Options not in the PPD */
+  ppd_file_t    *ppd = NULL;
 
  /*
   * Range check input...
@@ -95,6 +100,40 @@ cupsRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
   if (!h)
     return (-1);
 
+ /*
+  * If we have a PPD file (PPD environment variable), take it into
+  * account, by not parsing options which are in the PPD file here.
+  *
+  * They should get parsed and applied separately via the
+  * ppdRasterInterpretPPD() as that function parses the embedded
+  * PostScript code. This way weird things like Gutenprint's
+  * "Resolution" option (choice name is something odd, like
+  * 301x300dpi, and actual resolution can be completely different)
+  * will get treated correctly.
+  *
+  * We mark the option settings in the PPD and call
+  * ppdRasterInterpretPPD() only when we are called with set_defaults
+  * = 1. In any case we replace the option list we parse by a copy
+  * without the options of the PPD file.
+  */
+
+  ptr = getenv("PPD");
+  if (ptr && ptr[0] != '\0' && (ppd = ppdOpenFile(ptr)) != NULL)
+  {
+    if (set_defaults)
+    {
+      cupsMarkOptions(ppd, num_options, options);
+      cupsRasterInterpretPPD(h, ppd, num_options, options, NULL);
+    }
+    for (i = 0; i < num_options; i ++)
+      if (ppdFindOption(ppd, options[i].name) == NULL)
+       num_non_ppd_options =
+         cupsAddOption(options[i].name, options[i].value,
+                       num_non_ppd_options, &non_ppd_options);
+    num_options = num_non_ppd_options;
+    options = non_ppd_options;
+  }
+
  /*
   * Check if the supplied "media" option is a comma-separated list of any
   * combination of page size ("media"), media source ("media-position"),
@@ -1158,7 +1197,6 @@ cupsRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
   }
   else if (set_defaults)
     h->cupsRenderingIntent[0] = '\0';
-#endif /* HAVE_CUPS_1_7 */
 
   if (media_source != NULL)
     free(media_source);
@@ -1166,6 +1204,9 @@ cupsRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
     free(media_type);
   if (page_size != NULL)
     free(page_size);
+  if (num_non_ppd_options)
+    cupsFreeOptions(num_non_ppd_options, non_ppd_options);
+#endif /* HAVE_CUPS_1_7 */
 
   return (0);
 }