]> git.ipfire.org Git - thirdparty/cups-filters.git/commitdiff
libcupsfilters, universal: Add a universal filter function to replace chains of indiv...
authorpranshukharkwal <awesomepranshu@gmail.com>
Sun, 7 Nov 2021 17:24:54 +0000 (22:54 +0530)
committerGitHub <noreply@github.com>
Sun, 7 Nov 2021 17:24:54 +0000 (18:24 +0100)
To execute a print job CUPS usually has to turn the input data format into PDF, ptocess the PDF with page management functions, like N-up, only even/odd pages, page selection, scaling, ..., and then turn the PDF into a data format understood by the printer. For this it calls a chain of several filters in most cases which causes an overhead of starting individual processes and data input/output.

To reduce this overhead we have here a single, universal filter function which calls a chain of one or more suitable individual filter functions using the filterChain() filter function. It take the input and output format MIME types as parameters and automatically determines a suitable combination of filters to do the desired conversion.

For use with CUPS, to have (except printer drivers) only one single filter for everything, we have also a filter executable as for the individual filters and a MIME conversion rules file to tell CUPS that it converts a wide range of input formats into a wide range of output formats. To not require n * m lines in the conversion rule file to support n input and m output formats, we use an auxiliary input MIME type to reduce the number of lines to n + m, and to allow easy addition and modification of formats as each format is only mentioned once in the file.

This universal filter function is the GSoC 2021 project of Pranshu Kharkwal (Pull Request #421, https://gist.github.com/pranshukharkwal/9413499a6744049ef549159948392023). Thanks a lot!

.gitignore
Makefile.am
cupsfilters/filter.h
cupsfilters/universal.c [new file with mode: 0644]
filter/universal.c [new file with mode: 0644]
mime/universal.convs [new file with mode: 0644]
mime/universal.types [new file with mode: 0644]

index 81957b7959064005ebc6c2510bf9392fd86a53c5..6183006f45d112b56cfa9aa5d3b413d24f54e3f3 100644 (file)
@@ -98,6 +98,7 @@ testcmyk
 testdither
 testimage
 testrgb
+universal
 .vscode/
 
 #files generated by ./autogen.sh ./configure && make
index 6e593cde64ffb5104329109da1b81624fa23ded0..e327a1a79570e21d14bf535cfcbab7f50cd39783 100644 (file)
@@ -513,6 +513,7 @@ libcupsfilters_la_SOURCES = \
        cupsfilters/srgb.c \
        cupsfilters/texttopdf.c \
        cupsfilters/texttotext.c \
+       cupsfilters/universal.c \
        $(pkgfiltersinclude_DATA)
 EXTRA_libcupsfilters_la_SOURCES = \
        cupsfilters/getline.c \
@@ -811,7 +812,8 @@ pkgfilter_PROGRAMS += \
        bannertopdf \
        rastertops \
        pwgtoraster \
-       pclmtoraster
+       pclmtoraster \
+       universal
 if ENABLE_RASTERTOPWG
 pkgfilter_PROGRAMS += \
        rastertopwg
@@ -1150,6 +1152,14 @@ test_pdf2_CFLAGS = -I$(srcdir)/fontembed/ \
 test_pdf2_LDADD = libfontembed.la \
        libcupsfilters.la
 
+universal_SOURCES = \
+       filter/universal.c
+universal_CFLAGS = \
+       -I$(srcdir)/cupsfilters/ \
+       $(CUPS_CFLAGS)
+universal_LDADD = \
+       libcupsfilters.la \
+       $(CUPS_LIBS)
 
 # =====
 # UTILS
index 7462290778b2501d51c8167db281f03259a8e6e6..c871bdaa8bcfb6260bdc668728eb4547e423418d 100644 (file)
@@ -120,6 +120,12 @@ typedef struct texttopdf_parameter_s {  /* parameters container of environemnt
   const char *classification;
 } texttopdf_parameter_t;
 
+typedef struct filter_input_output_format_s { /* Contains input and output type
+                                            to be supplied to the universal function */
+  char *input_format;                 
+  char *output_format;
+} filter_input_output_format_t;
+
 /*
  * Prototypes...
  */
@@ -321,11 +327,22 @@ extern int texttopdf(int inputfd,
    classification (for overprint/watermark) */
 
 extern int texttotext(int inputfd,
-                    int outputfd,
-                    int inputseekable,
-                    filter_data_t *data,
-                    void *parameters);
+                       int outputfd,
+                       int inputseekable,
+                       filter_data_t *data,
+                       void *parameters);
 
+extern int universal(int inputfd,
+                     int outputfd,
+                     int inputseekable,
+                     filter_data_t *data,
+                     void *parameters);
+
+/*
+       Parameters: filter_input_output_format_t
+       Contains : Input_type : CONTENT_TYPE environment variable
+                          Output type : FINAL_CONTENT TYPE environment variable */
+                                               
 extern void filterSetCommonOptions(ppd_file_t *ppd,
                                   int num_options,
                                   cups_option_t *options,
diff --git a/cupsfilters/universal.c b/cupsfilters/universal.c
new file mode 100644 (file)
index 0000000..4b300c6
--- /dev/null
@@ -0,0 +1,243 @@
+#include "filter.h"
+#include <config.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <cups/cups.h>
+
+int                         /* O - Error status */
+universal(int inputfd,         /* I - File descriptor input stream */
+       int outputfd,        /* I - File descriptor output stream */
+       int inputseekable,   /* I - Is input stream seekable? (unused) */
+       filter_data_t *data, /* I - Job and printer data */
+       void *parameters)    /* I - Filter-specific parameters (outformat) */
+{
+    char *input;
+    char *output;
+    char *input_super = malloc(16);
+    char *input_type = malloc(256);
+    char *output_super = malloc(16);
+    char *output_type = malloc(256);
+    filter_out_format_t *outformat;
+    filter_filter_in_chain_t *filter , *next;
+    filter_input_output_format_t input_output_format;
+
+    input_output_format = *(filter_input_output_format_t *)parameters;
+    input = input_output_format.input_format;
+    output = input_output_format.output_format;
+    sscanf(input, "%15[^/]/%255s", input_super, input_type);
+    sscanf(output, "%15[^/]/%255s", output_super, output_type);
+
+    cups_array_t *filter_chain;
+    filter_chain = cupsArrayNew(NULL , NULL);
+
+    if(!strcmp(input_super , "image") && strcmp(input_type , "urf") && strcmp(input_type , "pwg-raster")){
+        if(!strcmp(output_type , "vnd.cups-raster") || !strcmp(output_type , "urf") || !strcmp(output_type , "pwg-raster") || !strcmp(output_type , "PCLm")){
+            filter = malloc(sizeof(filter_filter_in_chain_t));
+            filter->function = imagetoraster;
+            filter->parameters = NULL;
+            filter->name = "imagetoraster";
+            fprintf(stderr , "Adding %s to chain \n" , filter->name);
+            cupsArrayAdd(filter_chain , filter);
+
+            if(!strcmp(output , "image/pwg-raster")){
+                filter = malloc(sizeof(filter_filter_in_chain_t));
+                outformat = malloc(sizeof(filter_out_format_t));
+                *outformat = OUTPUT_FORMAT_PWG_RASTER;
+                filter->function = rastertopwg;
+                filter->parameters = outformat;
+                filter->name = "rastertopwg";
+                cupsArrayAdd(filter_chain , filter);
+                fprintf(stderr , "Adding %s to chain \n" , filter->name);
+            }
+            else if(!strcmp(output , "application/PCLm")){
+                outformat = malloc(sizeof(filter_out_format_t));
+                *outformat = OUTPUT_FORMAT_PCLM;
+                filter = malloc(sizeof(filter_filter_in_chain_t));
+                filter->function = rastertopdf;
+                filter->parameters = outformat;
+                filter->name = "rastertopclm";
+                fprintf(stderr , "Adding %s to chain \n" , filter->name);
+                cupsArrayAdd(filter_chain , filter);
+            }
+            else if(!strcmp(output , "image/urf")){
+                filter = malloc(sizeof(filter_filter_in_chain_t));
+                outformat = malloc(sizeof(filter_out_format_t));
+                *outformat = OUTPUT_FORMAT_APPLE_RASTER;
+                filter->function = rastertopwg;
+                filter->parameters = outformat;
+                filter->name = "rastertopwg";
+                cupsArrayAdd(filter_chain , filter);
+                fprintf(stderr , "Adding %s to chain \n" , filter->name);
+            }
+        }
+        else{
+            filter = malloc(sizeof(filter_filter_in_chain_t));
+            filter->function = imagetopdf;
+            filter->parameters = NULL;
+            filter->name = "imagetopdf";
+            fprintf(stderr , "Adding %s to chain \n" , filter->name);
+            cupsArrayAdd(filter_chain , filter);
+        }
+    }
+    else{
+        if(!strcmp(input , "application/postscript")){
+            outformat = malloc(sizeof(filter_out_format_t));
+            *outformat = OUTPUT_FORMAT_PDF;
+            filter = malloc(sizeof(filter_filter_in_chain_t));
+            filter->function = ghostscript;
+            filter->parameters = outformat;
+            filter->name = "gstopdf";
+            fprintf(stderr , "Adding %s to chain \n" , filter->name);
+            cupsArrayAdd(filter_chain , filter);
+        }
+        else if(!strcmp(input_super , "text") || (!strcmp(input_super , "application") && input_type[0] == 'x')){
+            filter = malloc(sizeof(filter_filter_in_chain_t));
+            texttopdf_parameter_t* parameters = (texttopdf_parameter_t *) malloc(sizeof(texttopdf_parameter_t));
+            char *p;
+            if ((p = getenv("CUPS_DATADIR")) != NULL)
+                parameters->data_dir = p;
+            else
+                parameters->data_dir = CUPS_DATADIR;
+
+            if ((p = getenv("CHARSET")) != NULL)
+                parameters->char_set = p;
+            else
+                parameters->char_set = NULL;
+
+            if ((p = getenv("CONTENT_TYPE")) != NULL)
+                parameters->content_type = p;
+            else
+                parameters->content_type = NULL;
+
+            if ((p = getenv("CLASSIFICATION")) != NULL)
+                parameters->classification = p;
+            else
+                parameters->classification = NULL;
+
+            filter->function = texttopdf;
+            filter->parameters = parameters;
+            filter->name = "texttopdf";
+            fprintf(stderr , "Adding %s to chain \n" , filter->name);
+            cupsArrayAdd(filter_chain , filter);
+        }
+        else if(!strcmp(input , "image/urf") || !strcmp(input , "image/pwg-raster") || !strcmp(input , "application/vnd.cups-raster")){
+            outformat = malloc(sizeof(filter_out_format_t));
+            *outformat = OUTPUT_FORMAT_PDF;
+            filter = malloc(sizeof(filter_filter_in_chain_t));
+            filter->function = rastertopdf;
+            filter->parameters = outformat;
+            filter->name = "rastertopdf";
+            fprintf(stderr , "Adding %s to chain \n" , filter->name);
+            cupsArrayAdd(filter_chain , filter);
+        }
+        else if(!strcmp(input_type , "vnd.adobe-reader-postscript")){
+            outformat = malloc(sizeof(filter_out_format_t));
+            *outformat = OUTPUT_FORMAT_CUPS_RASTER;
+            if(!strcmp(output_type , "pwg-raster")){
+                *outformat = OUTPUT_FORMAT_PWG_RASTER;
+            }
+            else if(!strcmp(output_type , "urf")){
+                *outformat = OUTPUT_FORMAT_APPLE_RASTER;
+            }
+            filter = malloc(sizeof(filter_filter_in_chain_t));
+            filter->function = ghostscript;
+            filter->parameters = outformat;
+            filter->name = "pstoraster";
+            cupsArrayAdd(filter_chain , filter);
+            fprintf(stderr , "Adding %s to chain \n" , filter->name);
+            
+            if(strcmp(output_type , "urf") && strcmp(output_type , "pwg-raster") && strcmp(output_type , "vnd.cups-raster")){
+                outformat = malloc(sizeof(filter_out_format_t));
+                *outformat = OUTPUT_FORMAT_PDF;
+                filter = malloc(sizeof(filter_filter_in_chain_t));
+                filter->function = rastertopdf;
+                filter->parameters = outformat;
+                filter->name = "rastertopdf";
+                fprintf(stderr , "Adding %s to chain \n" , filter->name);
+                cupsArrayAdd(filter_chain , filter);
+            }
+        }
+    }
+    if(((strcmp(input_super , "image") && strcmp(input_type , "vnd.adobe-reader-postscript")) || (strcmp(output_type , "vnd.cups-raster") && strcmp(output_type , "urf") && strcmp(output_type , "pwg-raster") && strcmp(output_type , "PCLm")) || !strcmp(input_type , "urf") || !strcmp(input_type , "pwg-raster"))){
+        if(strcmp(output_type , "pdf")){
+            filter = malloc(sizeof(filter_filter_in_chain_t));
+            filter->function = pdftopdf;
+            filter->parameters = NULL;
+            filter->name = "pdftopdf";
+            fprintf(stderr , "Adding %s to chain \n" , filter->name);
+            cupsArrayAdd(filter_chain , filter);
+
+            if(strcmp(output_type , "vnd.cups-pdf")){
+                if(!strcmp(output_type , "vnd.cups-raster") || !strcmp(output_type , "urf") || !strcmp(output_type , "pwg-raster") || !strcmp(output_type , "PCLm")){
+                    outformat = malloc(sizeof(filter_out_format_t));
+                    *outformat = OUTPUT_FORMAT_CUPS_RASTER;
+                    filter = malloc(sizeof(filter_filter_in_chain_t));
+                    filter->function = pdftoraster;
+                    filter->parameters = outformat;
+                    filter->name = "pdftoraster";
+                    cupsArrayAdd(filter_chain , filter);
+                    fprintf(stderr , "Adding %s to chain \n" , filter->name);
+
+                    if(!strcmp(output , "image/pwg-raster")){
+                        outformat = malloc(sizeof(filter_out_format_t));
+                        filter = malloc(sizeof(filter_filter_in_chain_t));
+                        *outformat = OUTPUT_FORMAT_PWG_RASTER;
+                        filter->function = rastertopwg;
+                        filter->parameters = outformat;
+                        filter->name = "rastertopwg";
+                        cupsArrayAdd(filter_chain , filter);
+                        fprintf(stderr , "Adding %s to chain \n" , filter->name);
+                    }
+                    else if(!strcmp(output , "application/PCLm")){
+                        outformat = malloc(sizeof(filter_out_format_t));
+                        *outformat = OUTPUT_FORMAT_PCLM;
+                        filter = malloc(sizeof(filter_filter_in_chain_t));
+                        filter->function = rastertopdf;
+                        filter->parameters = outformat;
+                        filter->name = "rastertopclm";
+                        fprintf(stderr , "Adding %s to chain \n" , filter->name);
+                        cupsArrayAdd(filter_chain , filter);
+                    }
+                    else if(!strcmp(output , "image/urf")){
+                        filter = malloc(sizeof(filter_filter_in_chain_t));
+                        outformat = malloc(sizeof(filter_out_format_t));
+                        *outformat = OUTPUT_FORMAT_APPLE_RASTER;
+                        filter->function = rastertopwg;
+                        filter->parameters = outformat;
+                        filter->name = "rastertopwg";
+                        cupsArrayAdd(filter_chain , filter);
+                        fprintf(stderr , "Adding %s to chain \n" , filter->name);
+                    }
+                }
+                else if(!strcmp(output , "application/postscript") || !strcmp(output , "application/vnd.cups-postscript")){
+                    filter = malloc(sizeof(filter_filter_in_chain_t));
+                    filter->function = pdftops;
+                    filter->parameters = NULL;
+                    filter->name = "pdftops";
+                    fprintf(stderr , "Adding %s to chain \n" , filter->name);
+                    cupsArrayAdd(filter_chain , filter);
+                }
+            }
+        }
+    }
+    
+    int ret = filterChain(inputfd , outputfd , inputseekable , data , filter_chain);
+
+    free(input_super);
+    free(input_type);
+    free(output_super);
+    free(output_type);
+    for (filter = (filter_filter_in_chain_t *)cupsArrayFirst(filter_chain); filter; filter = next){
+        next = (filter_filter_in_chain_t *)cupsArrayNext(filter_chain);
+        free(filter->parameters);
+        free(filter);
+    }
+    return ret;
+}
diff --git a/filter/universal.c b/filter/universal.c
new file mode 100644 (file)
index 0000000..9c9e668
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Include necessary headers...
+ */
+
+#include <cupsfilters/filter.h>
+#include <signal.h>
+
+
+/*
+ * Local globals...
+ */
+
+static int             JobCanceled = 0;/* Set to 1 on SIGTERM */
+
+
+/*
+ * Local functions...
+ */
+
+static void            cancel_job(int sig);
+
+
+/*
+ * 'main()' - Main entry.
+ */
+
+int                                    /* O - Exit status */
+main(int  argc,                                /* I - Number of command-line args */
+     char *argv[])                     /* I - Command-line arguments */
+{
+  int           ret;
+  filter_input_output_format_t input_output_format;
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+  struct sigaction action;             /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+ /*
+  * Register a signal handler to cleanly cancel a job.
+  */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+  sigset(SIGTERM, cancel_job);
+#elif defined(HAVE_SIGACTION)
+  memset(&action, 0, sizeof(action));
+
+  sigemptyset(&action.sa_mask);
+  action.sa_handler = cancel_job;
+  sigaction(SIGTERM, &action, NULL);
+#else
+  signal(SIGTERM, cancel_job);
+#endif /* HAVE_SIGSET */
+
+  input_output_format.input_format = getenv("CONTENT_TYPE");
+  input_output_format.output_format = getenv("FINAL_CONTENT_TYPE");
+  ret = filterCUPSWrapper(argc, argv, universal, &input_output_format , &JobCanceled);
+
+  if (ret)
+    fprintf(stderr, "ERROR: universal filter failed.\n");
+
+  return (ret);
+}
+
+
+/*
+ * 'cancel_job()' - Flag the job as canceled.
+ */
+
+static void
+cancel_job(int sig)                    /* I - Signal number (unused) */
+{
+  (void)sig;
+
+  JobCanceled = 1;
+}
+
diff --git a/mime/universal.convs b/mime/universal.convs
new file mode 100644 (file)
index 0000000..1ebc6da
--- /dev/null
@@ -0,0 +1,19 @@
+image/jpeg                           application/vnd.universal-input      0    -
+image/png                            application/vnd.universal-input      0    -
+image/gif                            application/vnd.universal-input      0    -
+image/pwg-raster                     application/vnd.universal-input      0    -
+application/vnd.cups-pdf             application/vnd.universal-input      0    -
+application/vnd.cups-raster          application/vnd.universal-input      0    -
+image/urf                            application/vnd.universal-input      0    -
+application/postscript               application/vnd.universal-input      0    -
+application/pdf                      application/vnd.universal-input      0    -
+text/plain                           application/vnd.universal-input      0    -
+application/PCLm                     application/vnd.universal-input      0    -
+application/vnd.universal-input      application/pdf                      0    universal
+application/vnd.universal-input      application/vnd.cups-pdf             0    universal
+application/vnd.universal-input      application/vnd.cups-postscript      0    universal
+application/vnd.universal-input      application/postscript               0    universal
+application/vnd.universal-input      application/vnd.cups-raster          0    universal
+application/vnd.universal-input      image/pwg-raster                     0    universal
+application/vnd.universal-input      image/urf                            0    universal
+application/vnd.universal-input      application/PCLm                     0    universal
diff --git a/mime/universal.types b/mime/universal.types
new file mode 100644 (file)
index 0000000..d51eb77
--- /dev/null
@@ -0,0 +1 @@
+application/vnd.universal-input