]> git.ipfire.org Git - thirdparty/cups-filters.git/commitdiff
libcupsfilters, pdftopdf: Convert pdftopdf to a filter function. 301/head
authorJai Luthra <luthrajaiji@gmail.com>
Tue, 25 Aug 2020 09:29:17 +0000 (14:59 +0530)
committerJai Luthra <luthrajaiji@gmail.com>
Sat, 29 Aug 2020 06:52:48 +0000 (12:22 +0530)
25 files changed:
Makefile.am
cupsfilters/filter.h
cupsfilters/pdftopdf/intervalset.cc [moved from filter/pdftopdf/intervalset.cc with 76% similarity]
cupsfilters/pdftopdf/intervalset.h [moved from filter/pdftopdf/intervalset.h with 91% similarity]
cupsfilters/pdftopdf/nup.cc [moved from filter/pdftopdf/nup.cc with 81% similarity]
cupsfilters/pdftopdf/nup.h [moved from filter/pdftopdf/nup.h with 96% similarity]
cupsfilters/pdftopdf/pdftopdf.cc [moved from filter/pdftopdf/pdftopdf.cc with 67% similarity]
cupsfilters/pdftopdf/pdftopdf.h [new file with mode: 0644]
cupsfilters/pdftopdf/pdftopdf_jcl.cc [moved from filter/pdftopdf/pdftopdf_jcl.cc with 100% similarity]
cupsfilters/pdftopdf/pdftopdf_jcl.h [moved from filter/pdftopdf/pdftopdf_jcl.h with 100% similarity]
cupsfilters/pdftopdf/pdftopdf_processor.cc [moved from filter/pdftopdf/pdftopdf_processor.cc with 71% similarity]
cupsfilters/pdftopdf/pdftopdf_processor.h [moved from filter/pdftopdf/pdftopdf_processor.h with 85% similarity]
cupsfilters/pdftopdf/pptypes.cc [moved from filter/pdftopdf/pptypes.cc with 67% similarity]
cupsfilters/pdftopdf/pptypes.h [moved from filter/pdftopdf/pptypes.h with 78% similarity]
cupsfilters/pdftopdf/qpdf_cm.cc [moved from filter/pdftopdf/qpdf_cm.cc with 100% similarity]
cupsfilters/pdftopdf/qpdf_cm.h [moved from filter/pdftopdf/qpdf_cm.h with 100% similarity]
cupsfilters/pdftopdf/qpdf_pdftopdf.cc [moved from filter/pdftopdf/qpdf_pdftopdf.cc with 100% similarity]
cupsfilters/pdftopdf/qpdf_pdftopdf.h [moved from filter/pdftopdf/qpdf_pdftopdf.h with 100% similarity]
cupsfilters/pdftopdf/qpdf_pdftopdf_processor.cc [moved from filter/pdftopdf/qpdf_pdftopdf_processor.cc with 91% similarity]
cupsfilters/pdftopdf/qpdf_pdftopdf_processor.h [moved from filter/pdftopdf/qpdf_pdftopdf_processor.h with 79% similarity]
cupsfilters/pdftopdf/qpdf_tools.cc [moved from filter/pdftopdf/qpdf_tools.cc with 100% similarity]
cupsfilters/pdftopdf/qpdf_tools.h [moved from filter/pdftopdf/qpdf_tools.h with 100% similarity]
cupsfilters/pdftopdf/qpdf_xobject.cc [moved from filter/pdftopdf/qpdf_xobject.cc with 100% similarity]
cupsfilters/pdftopdf/qpdf_xobject.h [moved from filter/pdftopdf/qpdf_xobject.h with 100% similarity]
filter/pdftopdf.c [new file with mode: 0644]

index 251f16d01ac84cbb044f47ed5e7081eae55ee32f..fcd3ca0ca572e7818be96d7aadea8b0a3e1d1337 100644 (file)
@@ -301,6 +301,28 @@ libcupsfilters_la_SOURCES = \
        cupsfilters/pack.c \
        cupsfilters/pclmtoraster.cxx \
        cupsfilters/pdf.cxx \
+       cupsfilters/pdftopdf/pdftopdf.cc \
+       cupsfilters/pdftopdf/pdftopdf.h \
+       cupsfilters/pdftopdf/pdftopdf_jcl.cc \
+       cupsfilters/pdftopdf/pdftopdf_jcl.h \
+       cupsfilters/pdftopdf/pdftopdf_processor.cc \
+       cupsfilters/pdftopdf/pdftopdf_processor.h \
+       cupsfilters/pdftopdf/qpdf_pdftopdf_processor.cc \
+       cupsfilters/pdftopdf/qpdf_pdftopdf_processor.h \
+       cupsfilters/pdftopdf/pptypes.cc \
+       cupsfilters/pdftopdf/pptypes.h \
+       cupsfilters/pdftopdf/nup.cc \
+       cupsfilters/pdftopdf/nup.h \
+       cupsfilters/pdftopdf/intervalset.cc \
+       cupsfilters/pdftopdf/intervalset.h \
+       cupsfilters/pdftopdf/qpdf_tools.cc \
+       cupsfilters/pdftopdf/qpdf_tools.h \
+       cupsfilters/pdftopdf/qpdf_xobject.cc \
+       cupsfilters/pdftopdf/qpdf_xobject.h \
+       cupsfilters/pdftopdf/qpdf_pdftopdf.cc \
+       cupsfilters/pdftopdf/qpdf_pdftopdf.h \
+       cupsfilters/pdftopdf/qpdf_cm.cc \
+       cupsfilters/pdftopdf/qpdf_cm.h \
        cupsfilters/pdftoippprinter.c \
        cupsfilters/pdftops.c \
        cupsfilters/ppdgenerator.c \
@@ -338,6 +360,7 @@ libcupsfilters_la_LDFLAGS = \
        -version-info 1
 if BUILD_DBUS
 libcupsfilters_la_CFLAGS += $(DBUS_CFLAGS) -DHAVE_DBUS
+libcupsfilters_CXXFLAGS = -std=c++0x $(libcupsfilters_CFLAGS)   # -std=c++11
 libcupsfilters_la_LIBADD += $(DBUS_LIBS)
 endif
 libcupsfilters_la_DEPENDENCIES = \
@@ -615,35 +638,14 @@ pkgfilterdir = $(CUPS_SERVERBIN)/filter
 pkgfilter_PROGRAMS += pdftopdf
 
 pdftopdf_SOURCES = \
-       filter/pdftopdf/pdftopdf.cc \
-       filter/pdftopdf/pdftopdf_jcl.cc \
-       filter/pdftopdf/pdftopdf_jcl.h \
-       filter/pdftopdf/pdftopdf_processor.cc \
-       filter/pdftopdf/pdftopdf_processor.h \
-       filter/pdftopdf/qpdf_pdftopdf_processor.cc \
-       filter/pdftopdf/qpdf_pdftopdf_processor.h \
-       filter/pdftopdf/pptypes.cc \
-       filter/pdftopdf/pptypes.h \
-       filter/pdftopdf/nup.cc \
-       filter/pdftopdf/nup.h \
-       filter/pdftopdf/intervalset.cc \
-       filter/pdftopdf/intervalset.h \
-       filter/pdftopdf/qpdf_tools.cc \
-       filter/pdftopdf/qpdf_tools.h \
-       filter/pdftopdf/qpdf_xobject.cc \
-       filter/pdftopdf/qpdf_xobject.h \
-       filter/pdftopdf/qpdf_pdftopdf.cc \
-       filter/pdftopdf/qpdf_pdftopdf.h \
-       filter/pdftopdf/qpdf_cm.cc \
-       filter/pdftopdf/qpdf_cm.h
+       filter/pdftopdf.c
 pdftopdf_CFLAGS = \
        -I$(srcdir)/ppd/ \
-       $(LIBQPDF_CFLAGS) \
+       -I$(srcdir)/cupsfilters/ \
        $(CUPS_CFLAGS)
-pdftopdf_CXXFLAGS = -std=c++0x $(pdftopdf_CFLAGS)   # -std=c++11
 pdftopdf_LDADD = \
        libppd.la \
-       $(LIBQPDF_LIBS) \
+       libcupsfilters.la \
        $(CUPS_LIBS)
 
 # ======================
index 0f63c1f2aabb44f77e723f89c77764ac7ec9a1d1..36bda22dbc4617ddd43a5d67803b0fc3f1122aa8 100644 (file)
@@ -101,6 +101,13 @@ extern int pclmtoraster(int inputfd,
                        filter_data_t *data,
                        void *parameters);
 
+extern int pdftopdf(int inputfd,
+                 int outputfd,
+                 int inputseekable,
+                 int *jobcanceled,
+                 filter_data_t *data,
+                 void *parameters);
+
 extern int pdftops(int inputfd,
                  int outputfd,
                  int inputseekable,
similarity index 76%
rename from filter/pdftopdf/intervalset.cc
rename to cupsfilters/pdftopdf/intervalset.cc
index 2967d597a398682ea87cd612f48ea42613536561..a624a2f44f68886f06728d4724eed8887a199055 100644 (file)
@@ -101,21 +101,27 @@ void IntervalSet::unite(value_t &aret,const value_t &b) const // {{{
 }
 // }}}
 
-void IntervalSet::dump() const // {{{
+void IntervalSet::dump(pdftopdf_doc_t *doc) const // {{{
 {
   int len=data.size();
   if (len==0) {
-    fprintf(stderr,"(empty)\n");
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+             "pdftopdf: (empty)\n");
     return;
   }
   len--;
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: ");
   for (int iA=0;iA<len;iA++) {
-    fprintf(stderr,"[%d,%d),",data[iA].first,data[iA].second);
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+             "[%d,%d),",data[iA].first,data[iA].second);
   }
   if (data[len].second==npos) {
-    fprintf(stderr,"[%d,inf)\n",data[len].first);
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+             "[%d,inf)\n",data[len].first);
   } else {
-    fprintf(stderr,"[%d,%d)\n",data[len].first,data[len].second);
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+             "[%d,%d)\n",data[len].first,data[len].second);
   }
 }
 // }}}
similarity index 91%
rename from filter/pdftopdf/intervalset.h
rename to cupsfilters/pdftopdf/intervalset.h
index 67b486fff299d3f24d80f321ad55e4d6500dc168..885b807def09fe870575be13031eb8b0e6c443f4 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef INTERVALSET_H_
 #define INTERVALSET_H_
 
+#include "pdftopdf.h"
 #include <stddef.h>
 #include <vector>
 
@@ -22,7 +23,7 @@ class IntervalSet {
   bool contains(key_t val) const;
   key_t next(key_t val) const;
 
-  void dump() const;
+  void dump(pdftopdf_doc_t *doc) const;
  private:
   // currently not used
   bool intersect(const value_t &a,const value_t &b) const;
similarity index 81%
rename from filter/pdftopdf/nup.cc
rename to cupsfilters/pdftopdf/nup.cc
index 8be9b86c15fb431abe22745ddee03af0f478a48c..6375576c30bb2d9a1a0d569d71973b9828a34cf7 100644 (file)
@@ -4,9 +4,10 @@
 #include <string.h>
 #include <utility>
 
-void NupParameters::dump() const // {{{
+void NupParameters::dump(pdftopdf_doc_t *doc) const // {{{
 {
-  fprintf(stderr,"NupX: %d, NupY: %d\n"
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: NupX: %d, NupY: %d\n"
                  "width: %f, height: %f\n",
                  nupX,nupY,
                  width,height);
@@ -23,28 +24,35 @@ void NupParameters::dump() const // {{{
     spos=1;
   }
   if (first==Axis::X) {
-    fprintf(stderr,"First Axis: X\n");
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: First Axis: X\n");
     opos=0;
   } else if (first==Axis::Y) {
-    fprintf(stderr,"First Axis: Y\n");
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: First Axis: Y\n");
     opos=2;
     std::swap(fpos,spos);
   }
 
   if ( (opos==-1)||(fpos==-1)||(spos==-1) ) {
-    fprintf(stderr,"Bad Spec: %d; start: %d, %d\n\n",
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: Bad Spec: %d; start: %d, %d\n\n",
                    first,xstart,ystart);
   } else {
     static const char *order[4]={"lr","rl","bt","tb"};
-    fprintf(stderr,"Order: %s%s\n",
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: Order: %s%s\n",
                    order[opos+fpos],order[(opos+2)%4+spos]);
   }
 
-  fputs("Alignment: ",stderr);
-  Position_dump(xalign,Axis::X);
-  fputs("/",stderr); 
-  Position_dump(yalign,Axis::Y);
-  fputs("\n",stderr);
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: Alignment: ");
+  Position_dump(xalign,Axis::X,doc);
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+      "/");
+  Position_dump(yalign,Axis::Y,doc);
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+      "\n");
 }
 // }}}
 
@@ -133,11 +141,12 @@ void NupState::reset() // {{{
 }
 // }}}
 
-void NupPageEdit::dump() const // {{{
+void NupPageEdit::dump(pdftopdf_doc_t *doc) const // {{{
 {
-  fprintf(stderr,"xpos: %f, ypos: %f, scale: %f\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: xpos: %f, ypos: %f, scale: %f\n",
                  xpos,ypos,scale);
-  sub.dump();
+  sub.dump(doc);
 }
 // }}}
 
similarity index 96%
rename from filter/pdftopdf/nup.h
rename to cupsfilters/pdftopdf/nup.h
index 0523cc782a62abf389ef4fa1d8dbd80f884aaa3e..3fa443cca7cdb927c68e6626251ea684e11f8ea0 100644 (file)
@@ -31,7 +31,7 @@ struct NupParameters {
   static void preset(int nup,NupParameters &ret);
   static float calculate(int nup, float in_ratio, float out_ratio,NupParameters &ret); // returns "quality", 1 is best
 
-  void dump() const;
+  void dump(pdftopdf_doc_t *doc) const;
 };
 
 // you get this
@@ -47,7 +47,7 @@ struct NupPageEdit {
   // everything in "outer"-page coordinates
   PageRect sub;
 
-  void dump() const;
+  void dump(pdftopdf_doc_t *doc) const;
 };
 
 /*
similarity index 67%
rename from filter/pdftopdf/pdftopdf.cc
rename to cupsfilters/pdftopdf/pdftopdf.cc
index ad59b6d6190c7616b9d48f50ac17518ca0f1a056..1fae430d8a2e9b3c420093bb64e6f90c562ad6af 100644 (file)
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include "pdftopdf.h"
 
 #include "pdftopdf_processor.h"
 #include "pdftopdf_jcl.h"
 
 #include <stdarg.h>
-static void error(const char *fmt,...) // {{{
-{
-  va_list ap;
-  va_start(ap,fmt);
 
-  fputs("ERROR: ",stderr);
-  vfprintf(stderr,fmt,ap);
-  fputs("\n",stderr);
-
-  va_end(ap);
-}
-// }}}
 
 // namespace {}
 
@@ -149,7 +139,7 @@ static bool ppdGetDuplex(ppd_file_t *ppd) // {{{
 // }}}
 
 // TODO: enum
-static bool ppdDefaultOrder(ppd_file_t *ppd) // {{{  -- is reverse?
+static bool ppdDefaultOrder(ppd_file_t *ppd, pdftopdf_doc_t *doc) // {{{  -- is reverse?
 {
   ppd_choice_t *choice;
   ppd_attr_t *attr;
@@ -169,7 +159,9 @@ static bool ppdDefaultOrder(ppd_file_t *ppd) // {{{  -- is reverse?
   } else if (strcasecmp(val,"Reverse")==0||(strcasecmp(val,"reverse-order")==0)) {
     return true;
   }
-  error("Unsupported output-order value %s, using 'normal'!",val);
+
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Unsupported output-order value %s, using 'normal'!",val);
   return false;
 }
 // }}}
@@ -301,7 +293,7 @@ static bool parseBorder(const char *val,BorderType &ret) // {{{
 }
 // }}}
 
-void getParameters(ppd_file_t *ppd,int num_options,cups_option_t *options,ProcessingParameters &param) // {{{
+void getParameters(ppd_file_t *ppd,int num_options,cups_option_t *options,ProcessingParameters &param,char *final_content_type,pdftopdf_doc_t *doc) // {{{
 {
   const char *val;
 
@@ -376,7 +368,8 @@ void getParameters(ppd_file_t *ppd,int num_options,cups_option_t *options,Proces
      *   3: 0 degrees,  4: 90 degrees,  5: -90 degrees,  6: 180 degrees
      */
     if ((ipprot<3)||(ipprot>6)) {
-      error("Bad value (%d) for orientation-requested, using 0 degrees",ipprot);
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Bad value (%d) for orientation-requested, using 0 degrees",ipprot);
     } else {
       static const Rotation ipp2rot[4]={ROT_0, ROT_90, ROT_270, ROT_180};
       param.orientation=ipp2rot[ipprot-3];
@@ -402,7 +395,7 @@ void getParameters(ppd_file_t *ppd,int num_options,cups_option_t *options,Proces
        (val = cupsGetOption("page-size", num_options, options)) != NULL ||
        (val = cupsGetOption("PageSize", num_options, options)) != NULL) {
       pwg_media_t *size_found = NULL;
-      fprintf(stderr, "DEBUG: Page size from command line: %s\n", val);
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG, "pdftopdf: Page size from command line: %s\n", val);
       if ((size_found = pwgMediaForPWG(val)) == NULL)
        if ((size_found = pwgMediaForPPD(val)) == NULL)
          size_found = pwgMediaForLegacy(val);
@@ -413,10 +406,10 @@ void getParameters(ppd_file_t *ppd,int num_options,cups_option_t *options,Proces
        param.page.right=param.page.left=18.0;
        param.page.right=param.page.width-param.page.right;
        param.page.top=param.page.height-param.page.top;
-       fprintf(stderr, "DEBUG: Width: %f, Length: %f\n", param.page.width, param.page.height);
+       if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG, "pdftopdf: Width: %f, Length: %f\n", param.page.width, param.page.height);
       }
       else
-       fprintf(stderr, "DEBUG: Unsupported page size %s.\n", val);
+       if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG, "pdftopdf: Unsupported page size %s.\n", val);
     }
   }
 #endif /* HAVE_CUPS_1_7 */
@@ -467,7 +460,8 @@ void getParameters(ppd_file_t *ppd,int num_options,cups_option_t *options,Proces
       param.duplex=true;
       param.setDuplex=true;
     } else if (strcasecmp(val,"one-sided")!=0) {
-      error("Unsupported sides value %s, using sides=one-sided!",val);
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Unsupported sides value %s, using sides=one-sided!",val);
     }
   }
 
@@ -475,7 +469,8 @@ void getParameters(ppd_file_t *ppd,int num_options,cups_option_t *options,Proces
   int nup=1;
   if (optGetInt("number-up",num_options,options,&nup)) {
     if (!NupParameters::possible(nup)) {
-      error("Unsupported number-up value %d, using number-up=1!",nup);
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Unsupported number-up value %d, using number-up=1!",nup);
       nup=1;
     }
 // TODO   ;  TODO? nup enabled? ... fitplot
@@ -485,7 +480,8 @@ void getParameters(ppd_file_t *ppd,int num_options,cups_option_t *options,Proces
 
   if ((val=cupsGetOption("number-up-layout",num_options,options)) != NULL) {
     if (!parseNupLayout(val,param.nup)) {
-      error("Unsupported number-up-layout %s, using number-up-layout=lrtb!",val);
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Unsupported number-up-layout %s, using number-up-layout=lrtb!",val);
       param.nup.first=Axis::X;
       param.nup.xstart=Position::LEFT;
       param.nup.ystart=Position::TOP;
@@ -494,7 +490,8 @@ void getParameters(ppd_file_t *ppd,int num_options,cups_option_t *options,Proces
 
   if ((val=cupsGetOption("page-border",num_options,options)) != NULL) {
     if (!parseBorder(val,param.border)) {
-      error("Unsupported page-border value %s, using page-border=none!",val);
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Unsupported page-border value %s, using page-border=none!",val);
       param.border=BorderType::NONE;
     }
   }
@@ -505,7 +502,7 @@ void getParameters(ppd_file_t *ppd,int num_options,cups_option_t *options,Proces
     param.reverse = (strcasecmp(val, "Reverse") == 0 ||
                     strcasecmp(val, "reverse-order") == 0);
   } else if (ppd) {
-    param.reverse=ppdDefaultOrder(ppd);
+    param.reverse=ppdDefaultOrder(ppd, doc);
   }
 
   std::string rawlabel;
@@ -536,7 +533,8 @@ void getParameters(ppd_file_t *ppd,int num_options,cups_option_t *options,Proces
     } else if (strcasecmp(val,"odd")==0) {
       param.evenPages=false;
     } else if (strcasecmp(val,"all")!=0) {
-      error("Unsupported page-set value %s, using page-set=all!",val);
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Unsupported page-set value %s, using page-set=all!",val);
     }
   }
 
@@ -563,20 +561,23 @@ void getParameters(ppd_file_t *ppd,int num_options,cups_option_t *options,Proces
     } else if (is_true(val)) {
       param.booklet=BookletMode::BOOKLET_ON;
     } else if (!is_false(val)) {
-      error("Unsupported booklet value %s, using booklet=off!",val);
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Unsupported booklet value %s, using booklet=off!",val);
     }
   }
   param.bookSignature=-1;
   if (optGetInt("booklet-signature",num_options,options,&param.bookSignature)) {
     if (param.bookSignature==0) {
-      error("Unsupported booklet-signature value, using booklet-signature=-1 (all)!",val);
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Unsupported booklet-signature value, using booklet-signature=-1 (all)!",val);
       param.bookSignature=-1;
     }
   }
 
   if ((val=cupsGetOption("position",num_options,options)) != NULL) {
     if (!parsePosition(val,param.xpos,param.ypos)) {
-      error("Unrecognized position value %s, using position=center!",val);
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Unrecognized position value %s, using position=center!",val);
       param.xpos=Position::CENTER;
       param.ypos=Position::CENTER;
     }
@@ -652,18 +653,19 @@ bool checkFeature(const char *feature, int num_options, cups_option_t *options)
   if ((val=cupsGetOption("page-logging",num_options,options)) != NULL) {
     if (strcasecmp(val,"auto") == 0) {
       param.page_logging = -1;
-      fprintf(stderr,
-             "DEBUG: pdftopdf: Automatic page logging selected by command line.\n");
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+             "pdftopdf: Automatic page logging selected by command line.\n");
     } else if (is_true(val)) {
       param.page_logging = 1;
-      fprintf(stderr,
-             "DEBUG: pdftopdf: Forced page logging selected by command line.\n");
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+             "pdftopdf: Forced page logging selected by command line.\n");
     } else if (is_false(val)) {
       param.page_logging = 0;
-      fprintf(stderr,
-             "DEBUG: pdftopdf: Suppressed page logging selected by command line.\n");
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+             "pdftopdf: Suppressed page logging selected by command line.\n");
     } else {
-      error("Unsupported page-logging value %s, using page-logging=auto!",val);
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Unsupported page-logging value %s, using page-logging=auto!",val);
       param.page_logging = -1;
     }
   }
@@ -674,17 +676,16 @@ bool checkFeature(const char *feature, int num_options, cups_option_t *options)
     if (!ppd) {
       // If there is no PPD do not log when not requested by command line
       param.page_logging = 0;
-      fprintf(stderr,
-             "DEBUG: pdftopdf: No PPD file specified, could not determine whether to log pages or not, so turned off page logging.\n");
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+             "pdftopdf: No PPD file specified, could not determine whether to log pages or not, so turned off page logging.\n");
     } else {
-      char *final_content_type = getenv("FINAL_CONTENT_TYPE");
       char *lastfilter = NULL;
       if (final_content_type == NULL) {
        // No FINAL_CONTENT_TYPE env variable set, we cannot determine
        // whether we have to log pages, so do not log.
        param.page_logging = 0;
-       fprintf(stderr,
-               "DEBUG: pdftopdf: No FINAL_CONTENT_TYPE environment variable, could not determine whether to log pages or not, so turned off page logging.\n");
+       if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+        "pdftopdf: No FINAL_CONTENT_TYPE environment variable, could not determine whether to log pages or not, so turned off page logging.\n");
       // Proceed depending on number of cupsFilter(2) lines in PPD
       } else if (ppd->num_filters == 0) {
        // No filter line, manufacturer-supplied PostScript PPD
@@ -775,12 +776,13 @@ bool checkFeature(const char *feature, int num_options, cups_option_t *options)
            param.page_logging = 0;
          }
        } else {
-         error("pdftopdf: Last filter could not get determined, page logging turned off.");
+         if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Last filter could not get determined, page logging turned off.");
          param.page_logging = 0;
        }
       }
-      fprintf(stderr,
-             "DEBUG: pdftopdf: Last filter determined by the PPD: %s; FINAL_CONTENT_TYPE: %s => pdftopdf will %slog pages in page_log.\n",
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+             "pdftopdf: Last filter determined by the PPD: %s; FINAL_CONTENT_TYPE: %s => pdftopdf will %slog pages in page_log.\n",
              (lastfilter ? lastfilter : "None"), final_content_type,
              (param.page_logging == 0 ? "not " : ""));
     }
@@ -803,7 +805,7 @@ static bool printerWillCollate(ppd_file_t *ppd) // {{{
 }
 // }}}
 
-void calculate(ppd_file_t *ppd,ProcessingParameters &param) // {{{
+void calculate(ppd_file_t *ppd,ProcessingParameters &param,char *final_content_type) // {{{
 {
   if (param.reverse)
     // Enable evenDuplex or the first page may be empty.
@@ -822,7 +824,6 @@ void calculate(ppd_file_t *ppd,ProcessingParameters &param) // {{{
       // of a driverless IPP printer (PDF, Apple Raster, PWG Raster, PCLm).
       // These printers do always hardware collate if they do hardware copies.
       // https://github.com/apple/cups/issues/5433
-      char *final_content_type = getenv("FINAL_CONTENT_TYPE");
       if (final_content_type &&
          (strcasestr(final_content_type, "/pdf") ||
           strcasestr(final_content_type, "/vnd.cups-pdf") ||
@@ -869,7 +870,7 @@ void calculate(ppd_file_t *ppd,ProcessingParameters &param) // {{{
 // }}}
 
 // reads from stdin into temporary file. returns FILE *  or NULL on error
-FILE *copy_stdin_to_temp() // {{{
+FILE *copy_stdin_to_temp(pdftopdf_doc_t *doc) // {{{
 {
   char buf[BUFSIZ];
   int n;
@@ -877,7 +878,8 @@ FILE *copy_stdin_to_temp() // {{{
   // FIXME:  what does >buf mean here?
   int fd=cupsTempFd(buf,sizeof(buf));
   if (fd<0) {
-    error("Can't create temporary file");
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Can't create temporary file");
     return NULL;
   }
   // remove name
@@ -886,20 +888,23 @@ FILE *copy_stdin_to_temp() // {{{
   // copy stdin to the tmp file
   while ((n=read(0,buf,BUFSIZ)) > 0) {
     if (write(fd,buf,n) != n) {
-      error("Can't copy stdin to temporary file");
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Can't copy stdin to temporary file");
       close(fd);
       return NULL;
     }
   }
   if (lseek(fd,0,SEEK_SET) < 0) {
-    error("Can't rewind temporary file");
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Can't rewind temporary file");
     close(fd);
     return NULL;
   }
 
   FILE *f;
   if ((f=fdopen(fd,"rb")) == 0) {
-    error("Can't fdopen temporary file");
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Can't fdopen temporary file");
     close(fd);
     return NULL;
   }
@@ -922,369 +927,106 @@ bool is_empty(FILE *f) // {{{
 }
 // }}}
 
-static int
-sub_process_spawn (const char *filename,
-          cups_array_t *sub_process_args,
-          FILE *fp) // {{{
-{
-  char *argument;
-  char buf[BUFSIZ];
-  char **sub_process_argv;
-  const char* apos;
-  int fds[2];
-  int i;
-  int n;
-  int numargs;
-  int pid;
-  int status = 65536;
-  int wstatus;
-
-  /* Put sub-process command line argument into an array for the "exec()"
-     call */
-  numargs = cupsArrayCount(sub_process_args);
-  sub_process_argv = (char **)calloc(numargs + 1, sizeof(char *));
-  for (argument = (char *)cupsArrayFirst(sub_process_args), i = 0; argument;
-       argument = (char *)cupsArrayNext(sub_process_args), i++) {
-    sub_process_argv[i] = argument;
-  }
-  sub_process_argv[i] = NULL;
-
-  /* Debug output: Full sub-process command line */
-  fprintf(stderr, "DEBUG: PDF form flattening command line:");
-  for (i = 0; sub_process_argv[i]; i ++) {
-    if ((strchr(sub_process_argv[i],' ')) || (strchr(sub_process_argv[i],'\t')))
-      apos = "'";
-    else
-      apos = "";
-    fprintf(stderr, " %s%s%s", apos, sub_process_argv[i], apos);
-  }
-  fprintf(stderr, "\n");
-
-  /* Create a pipe for feeding the job into sub-process */
-  if (pipe(fds))
-  {
-    fds[0] = -1;
-    fds[1] = -1;
-    fprintf(stderr, "ERROR: Unable to establish pipe for sub-process call\n");
-    goto out;
-  }
-
-  /* Set the "close on exec" flag on each end of the pipe... */
-  if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
-  {
-    close(fds[0]);
-    close(fds[1]);
-    fds[0] = -1;
-    fds[1] = -1;
-    fprintf(stderr, "ERROR: Unable to set \"close on exec\" flag on read end of the pipe for sub-process call\n");
-    goto out;
-  }
-  if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
-  {
-    close(fds[0]);
-    close(fds[1]);
-    fprintf(stderr, "ERROR: Unable to set \"close on exec\" flag on write end of the pipe for sub-process call\n");
-    goto out;
-  }
-
-  if ((pid = fork()) == 0)
-  {
-    /* Couple pipe with STDIN of sub-process */
-    if (fds[0] != 0) {
-      close(0);
-      if (fds[0] > 0) {
-        if (dup(fds[0]) < 0) {
-         fprintf(stderr, "ERROR: Unable to couple pipe with STDIN of sub-process\n");
-         goto out;
-       }
-      } else {
-        fprintf(stderr, "ERROR: Unable to couple pipe with STDIN of sub-process\n");
-        goto out;
-      }
-    }
-    close(fds[1]);
-
-    /* Execute sub-process command line ... */
-    execvp(filename, sub_process_argv);
-    perror(filename);
-    close(fds[0]);
-    goto out;
-  }
 
-  close(fds[0]);
-  /* Feed job data into the sub-process */
-  while ((n = fread(buf, 1, BUFSIZ, fp)) > 0) {
-    int count;
-retry_write:
-    count = write(fds[1], buf, n);
-    if (count != n) {
-      if (count == -1) {
-        if (errno == EINTR) {
-          goto retry_write;
-       }
-        fprintf(stderr, "ERROR: write failed: %s\n", strerror(errno));
-      }
-      fprintf(stderr, "ERROR: Can't feed job data into the sub-process\n");
-      goto out;
-    }
-  }
-  close (fds[1]);
-
-retry_wait:
-  if (waitpid (pid, &wstatus, 0) == -1) {
-    if (errno == EINTR)
-      goto retry_wait;
-    perror ("sub-process");
-    goto out;
-  }
+int                         /* O - Error status */
+pdftopdf(int inputfd,         /* I - File descriptor input stream */
+       int outputfd,        /* I - File descriptor output stream */
+       int inputseekable,   /* I - Is input stream seekable? (unused) */
+       int *jobcanceled,    /* I - Pointer to integer marking
+                                  whether job is canceled */
+       filter_data_t *data, /* I - Job and printer data */
+       void *parameters)    /* I - Filter-specific parameters (unused) */
+{
+  pdftopdf_doc_t     doc;         /* Document information */
+  filter_logfunc_t     log = data->logfunc;
+  void          *ld = data->logdata;
+  char *final_content_type = NULL;
 
-  /* How did the sub-process terminate */
-  if (WIFEXITED(wstatus))
-    /* Via exit() anywhere or return() in the main() function */
-    status = WEXITSTATUS(wstatus);
-  else if (WIFSIGNALED(wstatus))
-    /* Via signal */
-    status = 256 * WTERMSIG(wstatus);
-
-out:
-  free(sub_process_argv);
-  return status;
-}
-// }}}
+  (void)inputseekable;
 
-int main(int argc,char **argv)
-{
-  if ((argc<6)||(argc>7)) {
-    fprintf(stderr,"Usage: %s job-id user title copies options [file]\n",argv[0]);
-#ifdef DEBUG
-    ProcessingParameters param;
-    std::unique_ptr<PDFTOPDF_Processor> proc1(PDFTOPDF_Factory::processor());
-    param.page.width=595.276; // A4
-    param.page.height=841.89;
-
-    param.page.top=param.page.bottom=36.0;
-    param.page.right=param.page.left=18.0;
-    param.page.right=param.page.width-param.page.right;
-    param.page.top=param.page.height-param.page.top;
-
-    //param.nup.calculate(4,0.707,0.707,param.nup);
-    param.nup.nupX=2;
-    param.nup.nupY=2;
-    //param.nup.yalign=TOP;
-    param.border=BorderType::NONE;
-    //param.fillprint = true;
-    //param.mirror=true;
-    //param.reverse=true;
-    //param.numCopies=3;
-    if (!proc1->loadFilename("in.pdf",1)) return 2;
-    param.dump();
-    if (!processPDFTOPDF(*proc1,param)) return 3;
-    emitComment(*proc1,param);
-    proc1->emitFilename("out.pdf");
-#endif
-    return 1;
-  }
+  if (parameters)
+    final_content_type = (char *)parameters;
 
   try {
     ProcessingParameters param;
 
-    param.jobId=atoi(argv[1]);
-    param.user=argv[2];
-    param.title=argv[3];
-    param.numCopies=atoi(argv[4]);
-    param.copies_to_be_logged=atoi(argv[4]);
+    param.jobId=data->job_id;
+    param.user=data->job_user;
+    param.title=data->job_title;
+    param.numCopies=data->copies;
+    param.copies_to_be_logged=data->copies;
 
     // TODO?! sanity checks
 
-    int num_options=0;
-    cups_option_t *options=NULL;
-    num_options=cupsParseOptions(argv[5],num_options,&options);
+    doc.JobCanceled = jobcanceled;
+    doc.logdata = ld;
+    doc.logfunc = log;
 
-    ppd_file_t *ppd=NULL;
-    ppd=ppdOpenFile(getenv("PPD")); // getenv (and thus ppd) may be null. This will not cause problems.
-    ppdMarkDefaults(ppd);
+    if (data->ppdfile == NULL && data->ppd == NULL)
+    {
+      char *p = getenv("PPD");
+
+      if (p)
+        data->ppdfile = strdup(p);
+    }
+
+    if (data->ppdfile)
+      data->ppd = ppdOpenFile(data->ppdfile);
+
+    ppdMarkDefaults(data->ppd);
 
-    ppdMarkOptions(ppd,num_options,options);
+    ppdMarkOptions(data->ppd,data->num_options,data->options);
 
-    getParameters(ppd,num_options,options,param);
-    calculate(ppd,param);
+    getParameters(data->ppd,data->num_options,data->options,param,final_content_type,&doc);
+    calculate(data->ppd,param,final_content_type);
 
 #ifdef DEBUG
-    param.dump();
+    param.dump(&doc);
 #endif
 
-    /* Check with which method we will flatten interactive PDF forms
-       and annotations so that they get printed also after page
-       manipulations (scaling, N-up, ...). Flattening means to
-       integrate the filled in data and the printable annotations into
-       the pages themselves instead of holding them in an extra
-       layer. Default method is using QPDF, alternatives are the
-       external utilities pdftocairo or Ghostscript, but these make
-       the processing slower, especially due to extra piping of the
-       data between processes. */
     int empty = 0;
-    int qpdf_flatten = 1;
-    int pdftocairo_flatten = 0;
-    int gs_flatten = 0;
-    int external_auto_flatten = 0;
-    const char *val;
-    if ((val = cupsGetOption("pdftopdf-form-flattening", num_options, options)) != NULL) {
-      if (strcasecmp(val, "qpdf") == 0 || strcasecmp(val, "internal") == 0 ||
-         strcasecmp(val, "auto") == 0) {
-       qpdf_flatten = 1;
-      } else if (strcasecmp(val, "external") == 0) {
-       qpdf_flatten = 0;
-       external_auto_flatten = 1;
-      } else if (strcasecmp(val, "pdftocairo") == 0) {
-       qpdf_flatten = 0;
-       pdftocairo_flatten = 1;
-      } else if (strcasecmp(val, "ghostscript") == 0 || strcasecmp(val, "gs") == 0) {
-       qpdf_flatten = 0;
-       gs_flatten = 1;
-      } else
-       fprintf(stderr,
-               "WARNING: Invalid value for \"pdftopdf-form-flattening\": \"%s\"\n", val);
-    }
-
-    cupsFreeOptions(num_options,options);
 
     std::unique_ptr<PDFTOPDF_Processor> proc(PDFTOPDF_Factory::processor());
 
     FILE *tmpfile = NULL;
-    if (argc==7) {
+
+    if (inputfd == 0)
+    {
+      tmpfile = copy_stdin_to_temp(&doc);
+      if (tmpfile && is_empty(tmpfile)) {
+        fclose(tmpfile);
+        // ppdClose(ppd);
+        empty = 1;
+      } else if ((!tmpfile)||
+      (!proc->loadFile(tmpfile, &doc, WillStayAlive, 1)))
+      {
+        // ppdClose(ppd);
+        return 1;
+      }
+    }
+    else
+    {
       FILE *f = NULL;
-      if ((f = fopen(argv[6], "rb")) == NULL) {
-        ppdClose(ppd);
+      if ((f = fdopen(inputfd, "rb")) == NULL) {
+        // ppdClose(ppd);
         return 1;
       } else if (is_empty(f)) {
        fclose(f);
-       ppdClose(ppd);
+       // ppdClose(ppd);
        empty = 1;
-      } else if (!proc->loadFilename(argv[6],qpdf_flatten)) {
+      } else if (!proc->loadFile(f, &doc, WillStayAlive, 1)) {
        fclose(f);
-        ppdClose(ppd);
+        // ppdClose(ppd);
         return 1;
-      } else
-       fclose(f);
-    } else {
-      tmpfile = copy_stdin_to_temp();
-      if (tmpfile && is_empty(tmpfile)) {
-       fclose(tmpfile);
-       ppdClose(ppd);
-       empty = 1;
-      } else if ((!tmpfile)||
-                (!proc->loadFile(tmpfile,WillStayAlive,qpdf_flatten))) {
-        ppdClose(ppd);
-       return 1;
       }
     }
 
     if(empty)
     {
-      fprintf(stderr, "DEBUG: Input is empty, outputting empty file.\n");
+      if (log) log(ld, FILTER_LOGLEVEL_DEBUG, "pdftopdf: Input is empty, outputting empty file.\n");
       return 0;
     }
 
-    /* If the input file contains a PDF form and we opted for not
-       using QPDF for flattening the form, we pipe the PDF through
-       pdftocairo or Ghostscript here */
-    if (!qpdf_flatten && proc->hasAcroForm()) {
-      /* Prepare the input file for being read by the form flattening
-        process */
-      FILE *infile = NULL;
-      if (argc == 7) {
-       /* We read from a named file */
-       infile = fopen(argv[6], "r");
-      } else {
-       /* We read from a temporary file */
-       if (tmpfile) rewind(tmpfile);
-       infile = tmpfile;
-      }
-      if (infile == NULL) {
-       error("Could not open the input file for flattening the PDF form!");
-       return 1;
-      }
-      /* Create a temporary file for the output of the flattened PDF */
-      char buf[BUFSIZ];
-      int fd = cupsTempFd(buf,sizeof(buf));
-      if (fd<0) {
-       error("Can't create temporary file for flattened PDF form!");
-       return 1;
-      }
-      FILE *outfile = NULL;
-      if ((outfile=fdopen(fd,"rb")) == 0) {
-       error("Can't fdopen temporary file for the flattened PDF form!");
-       close(fd);
-       return 1;
-      }
-      int flattening_done = 0;
-      const char *command;
-      cups_array_t *args;
-      /* Choose the utility to be used and create its command line */
-      if (pdftocairo_flatten || external_auto_flatten) {
-       /* Try pdftocairo first, the preferred utility for form-flattening */
-       command = CUPS_POPPLER_PDFTOCAIRO;
-       args = cupsArrayNew(NULL, NULL);
-       cupsArrayAdd(args, strdup(command));
-       cupsArrayAdd(args, strdup("-pdf"));
-       cupsArrayAdd(args, strdup("-"));
-       cupsArrayAdd(args, strdup(buf));
-       /* Run the pdftocairo form flattening process */
-       rewind(infile);
-       int status = sub_process_spawn (command, args, infile);
-       cupsArrayDelete(args);
-       if (status == 0)
-         flattening_done = 1;
-       else
-         error("Unable to execute pdftocairo for form flattening!");
-      }
-      if (flattening_done == 0 &&
-         (gs_flatten || external_auto_flatten)) {
-       /* Try Ghostscript */
-       command = CUPS_GHOSTSCRIPT;
-       args = cupsArrayNew(NULL, NULL);
-       cupsArrayAdd(args, strdup(command));
-       cupsArrayAdd(args, strdup("-dQUIET"));
-       cupsArrayAdd(args, strdup("-dSAFER"));
-       cupsArrayAdd(args, strdup("-dNOPAUSE"));
-       cupsArrayAdd(args, strdup("-dBATCH"));
-       cupsArrayAdd(args, strdup("-dNOINTERPOLATE"));
-       cupsArrayAdd(args, strdup("-dNOMEDIAATTRS"));
-       cupsArrayAdd(args, strdup("-sDEVICE=pdfwrite"));
-       cupsArrayAdd(args, strdup("-dShowAcroForm"));
-       cupsArrayAdd(args, strdup("-sstdout=%stderr"));
-       memmove(buf + 13, buf, sizeof(buf) - 13);
-       memcpy(buf, "-sOutputFile=", 13);
-       cupsArrayAdd(args, strdup(buf));
-       cupsArrayAdd(args, strdup("-"));
-       /* Run the Ghostscript form flattening process */
-       rewind(infile);
-       int status = sub_process_spawn (command, args, infile);
-       cupsArrayDelete(args);
-       if (status == 0)
-         flattening_done = 1;
-       else
-         error("Unable to execute Ghostscript for form flattening!");
-      }
-      if (flattening_done == 0) {
-       error("No suitable utility for flattening filled PDF forms available, no flattening performed. Filled in content will possibly not be printed.");
-       rewind(infile);
-      }
-      /* Clean up */
-      if (infile != tmpfile)
-       fclose(infile);
-      /* Load the flattened PDF file into our PDF processor */
-      if (flattening_done) {
-       rewind(outfile);
-       unlink(buf);
-       if (!proc->loadFile(outfile,TakeOwnership,0)) {
-         error("Unable to create a PDF processor on the flattened form!"); 
-         return 1;
-       }
-      }
-    } else if (qpdf_flatten)
-      fprintf(stderr, "DEBUG: PDF interactive form and annotation flattening done via QPDF\n");
-
 /* TODO
     // color management
 --- PPD:
@@ -1298,27 +1040,32 @@ int main(int argc,char **argv)
     }
 */
 
-    if (!processPDFTOPDF(*proc,param)) {
-      ppdClose(ppd);
+    if (!processPDFTOPDF(*proc,param,&doc)) {
+      // ppdClose(ppd);
       return 2;
     }
 
-    emitPreamble(ppd,param); // ppdEmit, JCL stuff
+    emitPreamble(data->ppd,param); // ppdEmit, JCL stuff
     emitComment(*proc,param); // pass information to subsequent filters via PDF comments
 
-    //proc->emitFile(stdout);
-    proc->emitFilename(NULL);
+    FILE *outputfp;
+    outputfp = fdopen(outputfd, "w");
+    if(outputfp == NULL) return 1;
+    proc->emitFile(outputfp, &doc, TakeOwnership);
+    // proc->emitFilename(NULL);
 
-    emitPostamble(ppd,param);
-    ppdClose(ppd);
+    emitPostamble(data->ppd,param);
+    // ppdClose(ppd);
     if (tmpfile)
       fclose(tmpfile);
   } catch (std::exception &e) {
     // TODO? exception type
-    error("Exception: %s",e.what());
+    if (log) log(ld, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Exception: %s",e.what());
     return 5;
   } catch (...) {
-    error("Unknown exception caught. Exiting.");
+    if (log) log(ld, FILTER_LOGLEVEL_ERROR,
+             "pdftopdf: Unknown exception caught. Exiting.");
     return 6;
   }
 
diff --git a/cupsfilters/pdftopdf/pdftopdf.h b/cupsfilters/pdftopdf/pdftopdf.h
new file mode 100644 (file)
index 0000000..b61d04c
--- /dev/null
@@ -0,0 +1,17 @@
+//
+// Copyright 2020 by Jai Luthra.
+//
+
+#ifndef PDFTOPDF_H
+#define PDFTOPDF_H
+
+#include <cupsfilters/filter.h>
+
+typedef struct                                   /***** Document information *****/
+{
+  filter_logfunc_t logfunc;           /* Log function */
+  void *logdata;                      /* Log data */
+  int *JobCanceled;                   /* Set to 1 by caller */
+} pdftopdf_doc_t;
+
+#endif
similarity index 71%
rename from filter/pdftopdf/pdftopdf_processor.cc
rename to cupsfilters/pdftopdf/pdftopdf_processor.cc
index 6d2d32ff58f3eb1d9725513708490aa1b343b685..53c6168b76e661c0d067ee14984722a5bbbce4db 100644 (file)
@@ -4,13 +4,15 @@
 #include <assert.h>
 #include <numeric>
 
-void BookletMode_dump(BookletMode bkm) // {{{
+void BookletMode_dump(BookletMode bkm,pdftopdf_doc_t *doc) // {{{
 {
   static const char *bstr[3]={"Off","On","Shuffle-Only"};
   if ((bkm<BOOKLET_OFF) || (bkm>BOOKLET_JUSTSHUFFLE)) {
-    fprintf(stderr,"(bad booklet mode: %d)",bkm);
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+      "(bad booklet mode: %d)",bkm);
   } else {
-    fputs(bstr[bkm],stderr);
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+      "%s",bstr[bkm]);
   }
 }
 // }}}
@@ -28,76 +30,102 @@ bool ProcessingParameters::withPage(int outno) const // {{{
 }
 // }}}
 
-void ProcessingParameters::dump() const // {{{
+void ProcessingParameters::dump(pdftopdf_doc_t *doc) const // {{{
 {
-  fprintf(stderr,"jobId: %d, numCopies: %d\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: jobId: %d, numCopies: %d\n",
          jobId,numCopies);
-  fprintf(stderr,"user: %s, title: %s\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: user: %s, title: %s\n",
          (user)?user:"(null)",(title)?title:"(null)");
-  fprintf(stderr,"fitplot: %s\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: fitplot: %s\n",
          (fitplot)?"true":"false");
 
-  page.dump();
+  page.dump(doc);
 
-  fprintf(stderr,"Rotation(CCW): ");
-  Rotation_dump(orientation);
-  fprintf(stderr,"\n");
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: Rotation(CCW): ");
+  Rotation_dump(orientation,doc);
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: \n");
 
-  fprintf(stderr,"paper_is_landscape: %s\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: paper_is_landscape: %s\n",
          (paper_is_landscape)?"true":"false");
 
-  fprintf(stderr,"duplex: %s\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: duplex: %s\n",
          (duplex)?"true":"false");
 
-  fprintf(stderr,"Border: ");
-  BorderType_dump(border);
-  fprintf(stderr,"\n");
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: Border: ");
+  BorderType_dump(border,doc);
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: \n");
 
-  nup.dump();
+  nup.dump(doc);
 
-  fprintf(stderr,"reverse: %s\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: reverse: %s\n",
          (reverse)?"true":"false");
 
-  fprintf(stderr,"evenPages: %s, oddPages: %s\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: evenPages: %s, oddPages: %s\n",
          (evenPages)?"true":"false",
          (oddPages)?"true":"false");
 
-  fprintf(stderr,"page range: ");
-  pageRange.dump();
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: page range: ");
+  pageRange.dump(doc);
 
-  fprintf(stderr,"mirror: %s\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: mirror: %s\n",
          (mirror)?"true":"false");
 
-  fprintf(stderr,"Position: ");
-  Position_dump(xpos,Axis::X);
-  fprintf(stderr,"/");
-  Position_dump(ypos,Axis::Y);
-  fprintf(stderr,"\n");
-
-  fprintf(stderr,"collate: %s\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: Position: ");
+  Position_dump(xpos,Axis::X,doc);
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+      "/");
+  Position_dump(ypos,Axis::Y,doc);
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+      "\n");
+
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: collate: %s\n",
          (collate)?"true":"false");
 
-  fprintf(stderr,"evenDuplex: %s\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: evenDuplex: %s\n",
          (evenDuplex)?"true":"false");
 
-  fprintf(stderr,"pageLabel: %s\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: pageLabel: %s\n",
          pageLabel.empty () ? "(none)" : pageLabel.c_str());
 
-  fprintf(stderr,"bookletMode: ");
-  BookletMode_dump(booklet);
-  fprintf(stderr,"\nbooklet signature: %d\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: bookletMode: ");
+  BookletMode_dump(booklet,doc);
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+      "\nbooklet signature: %d\n",
          bookSignature);
 
-  fprintf(stderr,"autoRotate: %s\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: autoRotate: %s\n",
          (autoRotate)?"true":"false");
 
-  fprintf(stderr,"emitJCL: %s\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: emitJCL: %s\n",
          (emitJCL)?"true":"false");
-  fprintf(stderr,"deviceCopies: %d\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: deviceCopies: %d\n",
          deviceCopies);
-  fprintf(stderr,"deviceCollate: %s\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: deviceCollate: %s\n",
          (deviceCollate)?"true":"false");
-  fprintf(stderr,"setDuplex: %s\n",
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: setDuplex: %s\n",
          (setDuplex)?"true":"false");
 }
 // }}}
@@ -142,10 +170,11 @@ std::vector<int> bookletShuffle(int numPages,int signature) // {{{
 }
 // }}}
 
-bool processPDFTOPDF(PDFTOPDF_Processor &proc,ProcessingParameters &param) // {{{
+bool processPDFTOPDF(PDFTOPDF_Processor &proc,ProcessingParameters &param,pdftopdf_doc_t *doc) // {{{
 {
-  if (!proc.check_print_permissions()) {
-    fprintf(stderr,"Not allowed to print\n");
+  if (!proc.check_print_permissions(doc)) {
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+             "pdftopdf: Not allowed to print\n");
     return false;
   }
 
@@ -156,7 +185,7 @@ bool processPDFTOPDF(PDFTOPDF_Processor &proc,ProcessingParameters &param) // {{
     proc.autoRotateAll(dst_lscape,param.normal_landscape);
   }
 
-  std::vector<std::shared_ptr<PDFTOPDF_PageHandle>> pages=proc.get_pages();
+  std::vector<std::shared_ptr<PDFTOPDF_PageHandle>> pages=proc.get_pages(doc);
   const int numOrigPages=pages.size();
 
   // TODO FIXME? elsewhere
@@ -216,7 +245,8 @@ bool processPDFTOPDF(PDFTOPDF_Processor &proc,ProcessingParameters &param) // {{
   }
 
   if(param.fillprint||param.cropfit){
-    fprintf(stderr,"[DEBUG]: Cropping input pdf and Enabling fitplot.\n");
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+             "pdftopdf: Cropping input pdf and Enabling fitplot.\n");
     if(param.noOrientation&&pages.size())
     {
       bool land = pages[0]->is_landscape(param.orientation);
@@ -226,7 +256,7 @@ bool processPDFTOPDF(PDFTOPDF_Processor &proc,ProcessingParameters &param) // {{
     for(int i=0;i<(int)pages.size();i++)
     {
       std::shared_ptr<PDFTOPDF_PageHandle> page = pages[i];
-      page->crop(param.page,param.orientation,param.xpos,param.ypos,!param.cropfit);
+      page->crop(param.page,param.orientation,param.xpos,param.ypos,!param.cropfit,doc);
     }
     param.fitplot = 1;
   }
@@ -249,11 +279,12 @@ bool processPDFTOPDF(PDFTOPDF_Processor &proc,ProcessingParameters &param) // {{
 
       // Log page in /var/log/cups/page_log
       if (param.page_logging == 1)
-       fprintf(stderr, "PAGE: %d %d\n", iA + 1, param.copies_to_be_logged);
+       if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+             "pdftopdf: PAGE: %d %d\n", iA + 1, param.copies_to_be_logged);
 
       if (shuffle[iA]>=numOrigPages) {
         // add empty page as filler
-        proc.add_page(proc.new_page(param.page.width,param.page.height),param.reverse);
+        proc.add_page(proc.new_page(param.page.width,param.page.height,doc),param.reverse);
        outputno++;
         continue; // no border, etc.
       }
@@ -318,7 +349,7 @@ bool processPDFTOPDF(PDFTOPDF_Processor &proc,ProcessingParameters &param) // {{
       std::shared_ptr<PDFTOPDF_PageHandle> page;
       if (shuffle[iA]>=numOrigPages) {
         // add empty page as filler
-        page=proc.new_page(param.page.width,param.page.height);
+        page=proc.new_page(param.page.width,param.page.height,doc);
       } else {
         page=pages[shuffle[iA]];
       }
@@ -354,10 +385,11 @@ bool processPDFTOPDF(PDFTOPDF_Processor &proc,ProcessingParameters &param) // {{
          // Log page in /var/log/cups/page_log
          outputno++;
          if (param.page_logging == 1)
-           fprintf(stderr, "PAGE: %d %d\n", outputno,
+           if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+             "pdftopdf: PAGE: %d %d\n", outputno,
                    param.copies_to_be_logged);
         }
-        curpage=proc.new_page(param.page.width,param.page.height);
+        curpage=proc.new_page(param.page.width,param.page.height,doc);
         outputpage++;
       }
       if (shuffle[iA]>=numOrigPages) {
@@ -411,16 +443,18 @@ bool processPDFTOPDF(PDFTOPDF_Processor &proc,ProcessingParameters &param) // {{
       // Log page in /var/log/cups/page_log
       outputno ++;
       if (param.page_logging == 1)
-       fprintf(stderr, "PAGE: %d %d\n", outputno, param.copies_to_be_logged);
+       if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+             "pdftopdf: PAGE: %d %d\n", outputno, param.copies_to_be_logged);
     }
   }
 
   if ((param.evenDuplex || !param.oddPages) && (outputno & 1)) {
     // need to output empty page to not confuse duplex
-    proc.add_page(proc.new_page(param.page.width,param.page.height),param.reverse);
+    proc.add_page(proc.new_page(param.page.width,param.page.height,doc),param.reverse);
     // Log page in /var/log/cups/page_log
     if (param.page_logging == 1)
-      fprintf(stderr, "PAGE: %d %d\n", outputno + 1, param.copies_to_be_logged);
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+             "pdftopdf: PAGE: %d %d\n", outputno + 1, param.copies_to_be_logged);
   }
 
   proc.multiply(param.numCopies,param.collate);
similarity index 85%
rename from filter/pdftopdf/pdftopdf_processor.h
rename to cupsfilters/pdftopdf/pdftopdf_processor.h
index ec7b2997b24be3f67f37244623a7d98a50fc6214..052d61ea718c202dd81c53ff15a6b0c24bf645ab 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "pptypes.h"
 #include "nup.h"
+#include "pdftopdf.h"
 #include "intervalset.h"
 #include <vector>
 #include <string>
@@ -103,7 +104,7 @@ ProcessingParameters()
 
   // helper functions
   bool withPage(int outno) const; // 1 based
-  void dump() const;
+  void dump(pdftopdf_doc_t *doc) const;
 };
 
 #include <stdio.h>
@@ -118,7 +119,7 @@ class PDFTOPDF_PageHandle {
   // fscale:  inverse_scale (from nup, fitplot)
   virtual void add_border_rect(const PageRect &rect,BorderType border,float fscale) =0;
   // TODO?! add standalone crop(...) method (not only for subpages)
-  virtual Rotation crop(const PageRect &cropRect,Rotation orientation,Position xpos,Position ypos,bool scale) =0;
+  virtual Rotation crop(const PageRect &cropRect,Rotation orientation,Position xpos,Position ypos,bool scale,pdftopdf_doc_t *doc) =0;
   virtual bool is_landscape(Rotation orientation) =0 ;
   virtual void add_subpage(const std::shared_ptr<PDFTOPDF_PageHandle> &sub,float xpos,float ypos,float scale,const PageRect *crop=NULL) =0;
   virtual void mirror() =0;
@@ -132,15 +133,15 @@ class PDFTOPDF_Processor { // abstract interface
   virtual ~PDFTOPDF_Processor() {}
 
   // TODO: ... qpdf wants password at load time
-  virtual bool loadFile(FILE *f,ArgOwnership take=WillStayAlive,int flatten_forms=1) =0;
-  virtual bool loadFilename(const char *name,int flatten_forms=1) =0;
+  virtual bool loadFile(FILE *f,pdftopdf_doc_t *doc,ArgOwnership take=WillStayAlive,int flatten_forms=1) =0;
+  virtual bool loadFilename(const char *name,pdftopdf_doc_t *doc,int flatten_forms=1) =0;
 
   // TODO? virtual bool may_modify/may_print/?
-  virtual bool check_print_permissions() =0;
+  virtual bool check_print_permissions(pdftopdf_doc_t *doc) =0;
 
-  virtual std::vector<std::shared_ptr<PDFTOPDF_PageHandle>> get_pages() =0; // shared_ptr because of type erasure (deleter)
+  virtual std::vector<std::shared_ptr<PDFTOPDF_PageHandle>> get_pages(pdftopdf_doc_t *doc) =0; // shared_ptr because of type erasure (deleter)
 
-  virtual std::shared_ptr<PDFTOPDF_PageHandle> new_page(float width,float height) =0;
+  virtual std::shared_ptr<PDFTOPDF_PageHandle> new_page(float width,float height,pdftopdf_doc_t *doc) =0;
 
   virtual void add_page(std::shared_ptr<PDFTOPDF_PageHandle> page,bool front) =0; // at back/front -- either from get_pages() or new_page()+add_subpage()-calls  (or [also allowed]: empty)
 
@@ -153,8 +154,8 @@ class PDFTOPDF_Processor { // abstract interface
 
   virtual void setComments(const std::vector<std::string> &comments) =0;
 
-  virtual void emitFile(FILE *dst,ArgOwnership take=WillStayAlive) =0;
-  virtual void emitFilename(const char *name) =0; // NULL -> stdout
+  virtual void emitFile(FILE *dst,pdftopdf_doc_t *doc,ArgOwnership take=WillStayAlive) =0;
+  virtual void emitFilename(const char *name,pdftopdf_doc_t *doc) =0; // NULL -> stdout
 
   virtual bool hasAcroForm() =0;
 };
@@ -169,6 +170,6 @@ class PDFTOPDF_Factory {
 std::vector<int> bookletShuffle(int numPages,int signature=-1);
 
 // This is all we want:
-bool processPDFTOPDF(PDFTOPDF_Processor &proc,ProcessingParameters &param);
+bool processPDFTOPDF(PDFTOPDF_Processor &proc,ProcessingParameters &param,pdftopdf_doc_t *doc);
 
 #endif
similarity index 67%
rename from filter/pdftopdf/pptypes.cc
rename to cupsfilters/pdftopdf/pptypes.cc
index 542176685191cb45aecf7054f276399339c0e880..3298e5b55828cc305f5434ea0399a3f7cacb5a19 100644 (file)
@@ -3,41 +3,48 @@
 #include <stdio.h>
 #include <assert.h>
 
-void Position_dump(Position pos) // {{{
+void Position_dump(Position pos,pdftopdf_doc_t *doc) // {{{
 {
   static const char *pstr[3]={"Left/Bottom","Center","Right/Top"};
   if ((pos < LEFT) || (pos > RIGHT)) {
-    fprintf(stderr,"(bad position: %d)",pos);
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: (bad position: %d)\n",pos);
   } else {
-    fputs(pstr[pos+1],stderr);
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: %s\n",pstr[pos+1]);
   }
 }
 // }}}
 
-void Position_dump(Position pos,Axis axis) // {{{
+void Position_dump(Position pos,Axis axis,pdftopdf_doc_t *doc) // {{{
 {
   assert((axis == Axis::X) || (axis == Axis::Y));
   if ((pos < LEFT) || (pos > RIGHT)) {
-    fprintf(stderr,"(bad position: %d)",pos);
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+      "(bad position: %d)",pos);
     return;
   }
   if (axis==Axis::X) {
     static const char *pxstr[3]={"Left","Center","Right"};
-    fputs(pxstr[pos+1],stderr);
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+      "%s", pxstr[pos+1]);
   } else {
     static const char *pystr[3]={"Bottom","Center","Top"};
-    fputs(pystr[pos+1],stderr);
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+      "%s",pystr[pos+1]);
   }
 }
 // }}}
 
-void Rotation_dump(Rotation rot) // {{{
+void Rotation_dump(Rotation rot,pdftopdf_doc_t *doc) // {{{
 {
   static const char *rstr[4]={"0 deg","90 deg","180 deg","270 deg"}; // CCW
   if ((rot < ROT_0) || (rot > ROT_270)) {
-    fprintf(stderr,"(bad rotation: %d)",rot);
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+      "(bad rotation: %d)",rot);
   } else {
-    fputs(rstr[rot],stderr);
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+      "%s",rstr[rot]);
   }
 }
 // }}}
@@ -60,13 +67,15 @@ Rotation operator-(Rotation rhs) // {{{
 }
 // }}}
 
-void BorderType_dump(BorderType border) // {{{
+void BorderType_dump(BorderType border,pdftopdf_doc_t *doc) // {{{
 {
   if ((border < NONE) || (border == 1) || (border > TWO_THICK)) {
-    fprintf(stderr,"(bad border: %d)",border);
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+      "(bad border: %d)",border);
   } else {
     static const char *bstr[6]={"None",NULL,"one thin","one thick","two thin","two thick"};
-    fputs(bstr[border],stderr);
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_CONTROL,
+      "%s",bstr[border]);
   }
 }
 // }}}
@@ -167,9 +176,10 @@ void PageRect::set(const PageRect &rhs) // {{{
 }
 // }}}
 
-void PageRect::dump() const // {{{
+void PageRect::dump(pdftopdf_doc_t *doc) const // {{{
 {
-  fprintf(stderr,"top: %f, left: %f, right: %f, bottom: %f\n"
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+      "pdftopdf: top: %f, left: %f, right: %f, bottom: %f\n"
          "width: %f, height: %f\n",
          top,left,right,bottom,
          width,height);
similarity index 78%
rename from filter/pdftopdf/pptypes.h
rename to cupsfilters/pdftopdf/pptypes.h
index 4f4df6d4d225f4e895a3e41c1f979e1cdefccf79..bff54f8a43c053dc09fdfff4aea23e111025caef 100644 (file)
@@ -1,17 +1,18 @@
 #ifndef PPTYPES_H_
 #define PPTYPES_H_
 
+#include "pdftopdf.h"
 #include <cmath> // NAN
 
 // namespace PPTypes {}   TODO?
 
 enum Axis { X, Y };
 enum Position { CENTER=0, LEFT=-1, RIGHT=1, TOP=1, BOTTOM=-1 }; // PS order
-void Position_dump(Position pos);
-void Position_dump(Position pos,Axis axis);
+void Position_dump(Position pos,pdftopdf_doc_t *doc);
+void Position_dump(Position pos,Axis axis,pdftopdf_doc_t *doc);
 
 enum Rotation { ROT_0, ROT_90, ROT_180, ROT_270 };  // CCW
-void Rotation_dump(Rotation rot);
+void Rotation_dump(Rotation rot,pdftopdf_doc_t *doc);
 Rotation operator+(Rotation lhs,Rotation rhs);
 Rotation operator-(Rotation lhs,Rotation rhs);
 Rotation operator-(Rotation rhs);
@@ -19,7 +20,7 @@ Rotation operator-(Rotation rhs);
 
 enum BorderType { NONE=0, ONE_THIN=2, ONE_THICK=3, TWO_THIN=4, TWO_THICK=5,
                   ONE=0x02, TWO=0x04, THICK=0x01};
-void BorderType_dump(BorderType border);
+void BorderType_dump(BorderType border,pdftopdf_doc_t *doc);
 
 struct PageRect {
 PageRect() : top(NAN),left(NAN),right(NAN),bottom(NAN),width(NAN),height(NAN) {}
@@ -31,7 +32,7 @@ PageRect() : top(NAN),left(NAN),right(NAN),bottom(NAN),width(NAN),height(NAN) {}
   void translate(float tx,float ty);
 
   void set(const PageRect &rhs); // only for rhs.* != NAN
-  void dump() const;
+  void dump(pdftopdf_doc_t *doc) const;
 };
 
 //  bool parseBorder(const char *val,BorderType &ret); // none,single,...,double-thick
similarity index 91%
rename from filter/pdftopdf/qpdf_pdftopdf_processor.cc
rename to cupsfilters/pdftopdf/qpdf_pdftopdf_processor.cc
index d06ca5f7736c4925bcc1cdded6b09b45db3a4c99..34e852bce253ac1bb59ed84f00cf71d8ce5299f7 100644 (file)
@@ -10,6 +10,7 @@
 #include "qpdf_tools.h"
 #include "qpdf_xobject.h"
 #include "qpdf_pdftopdf.h"
+#include "pdftopdf.h"
 
 // Use: content.append(debug_box(pe.sub,xpos,ypos));
 static std::string debug_box(const PageRect &box,float xshift,float yshift) // {{{
@@ -176,7 +177,7 @@ void QPDF_PDFTOPDF_PageHandle::add_border_rect(const PageRect &_rect,BorderType
  *  Trim Box is used for trimming the page in required size.
  *  scale tells if we need to scale input file.
  */
-Rotation QPDF_PDFTOPDF_PageHandle::crop(const PageRect &cropRect,Rotation orientation,Position xpos,Position ypos,bool scale)
+Rotation QPDF_PDFTOPDF_PageHandle::crop(const PageRect &cropRect,Rotation orientation,Position xpos,Position ypos,bool scale,pdftopdf_doc_t *doc)
 {
   page.assertInitialized();
   if(orientation==ROT_0||orientation==ROT_180)
@@ -212,7 +213,8 @@ Rotation QPDF_PDFTOPDF_PageHandle::crop(const PageRect &cropRect,Rotation orient
     final_w = std::min(width,pageWidth);
     final_h = std::min(height,pageHeight);
   }
-  fprintf(stderr,"After Cropping: %lf %lf %lf %lf\n",width,height,final_w,final_h);
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+             "pdftopdf: After Cropping: %lf %lf %lf %lf\n",width,height,final_w,final_h);
   double posw = (width-final_w)/2,
         posh = (height-final_h)/2;
   // posw, posh : Position along width and height respectively.
@@ -450,21 +452,9 @@ void QPDF_PDFTOPDF_Processor::closeFile() // {{{
 }
 // }}}
 
-void QPDF_PDFTOPDF_Processor::error(const char *fmt,...) // {{{
-{
-  va_list ap;
-
-  va_start(ap,fmt);
-  fputs("ERROR: ",stderr);
-  vfprintf(stderr,fmt,ap);
-  fputs("\n",stderr);
-  va_end(ap);
-}
-// }}}
-
 // TODO?  try/catch for PDF parsing errors?
 
-bool QPDF_PDFTOPDF_Processor::loadFile(FILE *f,ArgOwnership take,int flatten_forms) // {{{
+bool QPDF_PDFTOPDF_Processor::loadFile(FILE *f,pdftopdf_doc_t *doc,ArgOwnership take,int flatten_forms) // {{{
 {
   closeFile();
   if (!f) {
@@ -483,7 +473,8 @@ bool QPDF_PDFTOPDF_Processor::loadFile(FILE *f,ArgOwnership take,int flatten_for
     try {
       pdf->processFile("temp file",f,false);
     } catch (const std::exception &e) {
-      error("loadFile failed: %s",e.what());
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+        "pdftopdf: loadFile failed: %s",e.what());
       return false;
     }
     break;
@@ -491,12 +482,14 @@ bool QPDF_PDFTOPDF_Processor::loadFile(FILE *f,ArgOwnership take,int flatten_for
     try {
       pdf->processFile("temp file",f,true);
     } catch (const std::exception &e) {
-      error("loadFile failed: %s",e.what());
+      if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+        "pdftopdf: loadFile failed: %s",e.what());
       return false;
     }
     break;
   case MustDuplicate:
-    error("loadFile with MustDuplicate is not supported");
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+        "pdftopdf: loadFile with MustDuplicate is not supported");
     return false;
   }
   start(flatten_forms);
@@ -504,14 +497,15 @@ bool QPDF_PDFTOPDF_Processor::loadFile(FILE *f,ArgOwnership take,int flatten_for
 }
 // }}}
 
-bool QPDF_PDFTOPDF_Processor::loadFilename(const char *name,int flatten_forms) // {{{
+bool QPDF_PDFTOPDF_Processor::loadFilename(const char *name,pdftopdf_doc_t *doc,int flatten_forms) // {{{
 {
   closeFile();
   try {
     pdf.reset(new QPDF);
     pdf->processFile(name);
   } catch (const std::exception &e) {
-    error("loadFilename failed: %s",e.what());
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+        "pdftopdf: loadFilename failed: %s",e.what());
     return false;
   }
   start(flatten_forms);
@@ -548,21 +542,23 @@ void QPDF_PDFTOPDF_Processor::start(int flatten_forms) // {{{
 }
 // }}}
 
-bool QPDF_PDFTOPDF_Processor::check_print_permissions() // {{{
+bool QPDF_PDFTOPDF_Processor::check_print_permissions(pdftopdf_doc_t *doc) // {{{
 {
   if (!pdf) {
-    error("No PDF loaded");
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+        "pdftopdf: No PDF loaded");
     return false;
   }
   return pdf->allowPrintHighRes() || pdf->allowPrintLowRes(); // from legacy pdftopdf
 }
 // }}}
 
-std::vector<std::shared_ptr<PDFTOPDF_PageHandle>> QPDF_PDFTOPDF_Processor::get_pages() // {{{
+std::vector<std::shared_ptr<PDFTOPDF_PageHandle>> QPDF_PDFTOPDF_Processor::get_pages(pdftopdf_doc_t *doc) // {{{
 {
   std::vector<std::shared_ptr<PDFTOPDF_PageHandle>> ret;
   if (!pdf) {
-    error("No PDF loaded");
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+        "pdftopdf: No PDF loaded");
     assert(0);
     return ret;
   }
@@ -575,10 +571,11 @@ std::vector<std::shared_ptr<PDFTOPDF_PageHandle>> QPDF_PDFTOPDF_Processor::get_p
 }
 // }}}
 
-std::shared_ptr<PDFTOPDF_PageHandle> QPDF_PDFTOPDF_Processor::new_page(float width,float height) // {{{
+std::shared_ptr<PDFTOPDF_PageHandle> QPDF_PDFTOPDF_Processor::new_page(float width,float height,pdftopdf_doc_t *doc) // {{{
 {
   if (!pdf) {
-    error("No PDF loaded");
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+        "pdftopdf: No PDF loaded");
     assert(0);
     return std::shared_ptr<PDFTOPDF_PageHandle>();
   }
@@ -691,7 +688,7 @@ void QPDF_PDFTOPDF_Processor::setComments(const std::vector<std::string> &commen
 }
 // }}}
 
-void QPDF_PDFTOPDF_Processor::emitFile(FILE *f,ArgOwnership take) // {{{
+void QPDF_PDFTOPDF_Processor::emitFile(FILE *f,pdftopdf_doc_t *doc,ArgOwnership take) // {{{
 {
   if (!pdf) {
     return;
@@ -705,7 +702,8 @@ void QPDF_PDFTOPDF_Processor::emitFile(FILE *f,ArgOwnership take) // {{{
     out.setOutputFile("temp file",f,true);
     break;
   case MustDuplicate:
-    error("emitFile with MustDuplicate is not supported");
+    if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_ERROR,
+        "pdftopdf: emitFile with MustDuplicate is not supported");
     return;
   }
   if (hasCM) {
@@ -721,7 +719,7 @@ void QPDF_PDFTOPDF_Processor::emitFile(FILE *f,ArgOwnership take) // {{{
 }
 // }}}
 
-void QPDF_PDFTOPDF_Processor::emitFilename(const char *name) // {{{
+void QPDF_PDFTOPDF_Processor::emitFilename(const char *name,pdftopdf_doc_t *doc) // {{{
 {
   if (!pdf) {
     return;
@@ -742,7 +740,8 @@ void QPDF_PDFTOPDF_Processor::emitFilename(const char *name) // {{{
   if (len)
   out.write();
   else
-  fprintf(stderr, "DEBUG: No pages left, outputting empty file.\n");
+  if (doc->logfunc) doc->logfunc(doc->logdata, FILTER_LOGLEVEL_DEBUG,
+             "pdftopdf: No pages left, outputting empty file.\n");
 }
 // }}}
 
similarity index 79%
rename from filter/pdftopdf/qpdf_pdftopdf_processor.h
rename to cupsfilters/pdftopdf/qpdf_pdftopdf_processor.h
index f721d93909fb59cb8bc51ae52e15a102b13ed0b7..9e13348ab20182e01b836509f25db028a889ca9b 100644 (file)
@@ -12,7 +12,7 @@ class QPDF_PDFTOPDF_PageHandle : public PDFTOPDF_PageHandle {
   virtual void mirror();
   virtual void rotate(Rotation rot);
   virtual void add_label(const PageRect &rect, const std::string label);
-  virtual Rotation crop(const PageRect &cropRect,Rotation orientation,Position xpos,Position ypos,bool scale);
+  virtual Rotation crop(const PageRect &cropRect,Rotation orientation,Position xpos,Position ypos,bool scale,pdftopdf_doc_t *doc);
   virtual bool is_landscape(Rotation orientation);
   void debug(const PageRect &rect,float xpos,float ypos);
  private:
@@ -35,16 +35,16 @@ class QPDF_PDFTOPDF_PageHandle : public PDFTOPDF_PageHandle {
 
 class QPDF_PDFTOPDF_Processor : public PDFTOPDF_Processor {
  public:
-  virtual bool loadFile(FILE *f,ArgOwnership take=WillStayAlive,int flatten_forms=1);
-  virtual bool loadFilename(const char *name,int flatten_forms=1);
+  virtual bool loadFile(FILE *f,pdftopdf_doc_t *doc,ArgOwnership take=WillStayAlive,int flatten_forms=1);
+  virtual bool loadFilename(const char *name,pdftopdf_doc_t *doc,int flatten_forms=1);
 
   // TODO: virtual bool may_modify/may_print/?
-  virtual bool check_print_permissions();
+  virtual bool check_print_permissions(pdftopdf_doc_t *doc);
 
   // virtual bool setProcess(const ProcessingParameters &param) =0;
 
-  virtual std::vector<std::shared_ptr<PDFTOPDF_PageHandle>> get_pages();
-  virtual std::shared_ptr<PDFTOPDF_PageHandle> new_page(float width,float height);
+  virtual std::vector<std::shared_ptr<PDFTOPDF_PageHandle>> get_pages(pdftopdf_doc_t *doc);
+  virtual std::shared_ptr<PDFTOPDF_PageHandle> new_page(float width,float height,pdftopdf_doc_t *doc);
 
   virtual void add_page(std::shared_ptr<PDFTOPDF_PageHandle> page,bool front);
 
@@ -55,13 +55,12 @@ class QPDF_PDFTOPDF_Processor : public PDFTOPDF_Processor {
 
   virtual void setComments(const std::vector<std::string> &comments);
 
-  virtual void emitFile(FILE *dst,ArgOwnership take=WillStayAlive);
-  virtual void emitFilename(const char *name);
+  virtual void emitFile(FILE *dst,pdftopdf_doc_t *doc,ArgOwnership take=WillStayAlive);
+  virtual void emitFilename(const char *name,pdftopdf_doc_t *doc);
 
   virtual bool hasAcroForm();
  private:
   void closeFile();
-  void error(const char *fmt,...);
   void start(int flatten_forms);
  private:
   std::unique_ptr<QPDF> pdf;
diff --git a/filter/pdftopdf.c b/filter/pdftopdf.c
new file mode 100644 (file)
index 0000000..27867fe
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Pdf to pdf filter based on pdftopdf() filter function.
+ */
+
+
+/*
+ * 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;
+#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 */
+
+  ret = filterCUPSWrapper(argc, argv, pdftopdf, NULL, &JobCanceled);
+
+  if (ret)
+    fprintf(stderr, "ERROR: pdftopdf filter function 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;
+}