From f80c0042dcb782cdeb3840c630c9b522fbf55461 Mon Sep 17 00:00:00 2001 From: dh Date: Fri, 22 Feb 2019 21:25:33 +0530 Subject: [PATCH] Add crop-to-fit scaling feature. Input file is cropped and printed. We don't do scaling in crop-to-fit. Fixes #65. imagetoraster, imagetopdf and pdftopdf filters are mutually exclusive. "-o fill" option is now equivalent to "print-scaling=fill". --- filter/imagetopdf.c | 116 ++++++++++++++++----- filter/imagetoraster.c | 112 +++++++++++++++----- filter/pdftopdf/pdftopdf.cc | 15 +++ filter/pdftopdf/pdftopdf_processor.cc | 23 +++- filter/pdftopdf/pdftopdf_processor.h | 4 +- filter/pdftopdf/qpdf_pdftopdf_processor.cc | 22 ++-- filter/pdftopdf/qpdf_pdftopdf_processor.h | 2 +- 7 files changed, 228 insertions(+), 66 deletions(-) diff --git a/filter/imagetopdf.c b/filter/imagetopdf.c index 311e372aa..0bf2618dd 100644 --- a/filter/imagetopdf.c +++ b/filter/imagetopdf.c @@ -694,6 +694,7 @@ main(int argc, /* I - Number of command-line arguments */ ppd_attr_t *attr; int pl,pr; int fillprint = 0; /* print-scaling = fill */ + int cropfit = 0; /* -o crop-to-fit = true */ /* * Make sure status messages are not buffered... */ @@ -818,6 +819,21 @@ main(int argc, /* I - Number of command-line arguments */ fillprint = 1; } } + else if((val = cupsGetOption("fill",num_options,options))!=0) { + if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")) + { + fillprint = 1; + } + } + /* + * crop-to-fit + */ + if((val = cupsGetOption("crop-to-fit",num_options,options))!= NULL){ + if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")) + { + cropfit=1; + } + } if ((val = cupsGetOption("OutputOrder",num_options,options)) != 0) { if (!strcasecmp(val, "Reverse")) { @@ -981,26 +997,26 @@ main(int argc, /* I - Number of command-line arguments */ colorspace = ColorDevice ? CUPS_IMAGE_RGB_CMYK : CUPS_IMAGE_WHITE; img = cupsImageOpen(filename, colorspace, CUPS_IMAGE_WHITE, sat, hue, NULL); - - if(fillprint) + if(fillprint||cropfit) { float w = (float)cupsImageGetWidth(img); float h = (float)cupsImageGetHeight(img); float pw = PageRight-PageLeft; float ph = PageTop-PageBottom; - char temp[3072]; - char tempfilename[1024]; int tempOrientation = Orientation; - if ((cupsTempFd(tempfilename, sizeof(tempfilename))) < 0) - { - perror("ERROR: Unable to copy image file"); - return (1); - } char *val; + int flag = 3; if((val = cupsGetOption("orientation-requested",num_options,options))!=NULL) { tempOrientation = atoi(val); } + else if((val = cupsGetOption("landscape",num_options,options))!=NULL) + { + if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")) + { + tempOrientation = 4; + } + } if(tempOrientation>0) { if(tempOrientation==4||tempOrientation==5) @@ -1008,33 +1024,83 @@ main(int argc, /* I - Number of command-line arguments */ float temp = pw; pw = ph; ph = temp; + flag = 4; } } if(tempOrientation==0) { - float ratio = ph/pw; - if(h/w < ratio) + int temp1 = pw, + temp2 = ph, + temp3 = pw, + temp4 = ph; + if(temp1>w) temp1 = w; + if(temp2>h) temp2 = h; + if(temp3>h) temp3 = h; + if(temp4>w) temp4 = w; + if(temp1*temp2pw) + { + final_w = pw; + } + if(final_h>ph) + { + final_h = ph; + } + if((fabs(final_w-w)>0.5*w)||(fabs(final_h-h)>0.5*h)) + { + fprintf(stderr,"[DEBUG]: Ignoring crop-to-fit option!\n"); + cropfit=0; + } + else{ + float posw=(w-final_w)/2,posh=(h-final_h)/2; + posw = (1+XPosition)*posw; + posh = (1-YPosition)*posh; + cups_image_t *img2 = cupsImageCrop(img,posw,posh,final_w,final_h); + cupsImageClose(img); + img = img2; + if(flag==4) + { + PageBottom+=(PageTop-PageBottom-final_w)/2; + PageTop = PageBottom+final_w; + PageLeft +=(PageRight-PageLeft-final_h)/2; + PageRight = PageLeft+final_h; + } + else{ + PageBottom+=(PageTop-PageBottom-final_h)/2; + PageTop = PageBottom+final_h; + PageLeft +=(PageRight-PageLeft-final_w)/2; + PageRight = PageLeft+final_w; + } + if(PageBottom<0) PageBottom = 0; + if(PageLeft<0) PageLeft = 0; + } } - float posw=(w-final_w)/2,posh=(h-final_h)/2; - posw = (1+XPosition)*posw; - posh = (1-YPosition)*posh; - cups_image_t *img2 = cupsImageCrop(img,posw,posh,final_w,final_h); - cupsImageClose(img); - img = img2; } #if defined(USE_CONVERT_CMD) && defined(CONVERT_CMD) diff --git a/filter/imagetoraster.c b/filter/imagetoraster.c index 43faa015a..5b5674d8f 100644 --- a/filter/imagetoraster.c +++ b/filter/imagetoraster.c @@ -191,6 +191,7 @@ main(int argc, /* I - Number of command-line arguments */ cm_calibration_t cm_calibrate; /* Are we color calibrating the device? */ int cm_disabled; /* Color management disabled? */ int fillprint = 0; /* print-scaling = fill */ + int cropfit = 0; /* -o crop-to-fit */ /* * Make sure status messages are not buffered... */ @@ -394,6 +395,18 @@ main(int argc, /* I - Number of command-line arguments */ fillprint = 1; } } + else if((val = cupsGetOption("fill",num_options,options))!=0) { + if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")) + { + fillprint = 1; + } + } + if((val = cupsGetOption("crop-to-fit",num_options,options))!= NULL){ + if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")) + { + cropfit=1; + } + } if ((val = cupsGetOption("ppi", num_options, options)) != NULL) { @@ -696,24 +709,26 @@ main(int argc, /* I - Number of command-line arguments */ img = cupsImageOpen(filename, primary, secondary, sat, hue, lut); if(img!=NULL) { - if(fillprint) + if(fillprint||cropfit) { float w = (float)cupsImageGetWidth(img); float h = (float)cupsImageGetHeight(img); float pw = PageRight-PageLeft; float ph = PageTop-PageBottom; - char temp[3072],*val; - char tempfilename[1024]; + char *val; int tempOrientation = Orientation; - if ((cupsTempFd(tempfilename, sizeof(tempfilename))) < 0) - { - perror("ERROR: Unable to copy image file"); - return (1); - } + int flag =3; if((val = cupsGetOption("orientation-requested",num_options,options))!=NULL) { tempOrientation = atoi(val); } + else if((val = cupsGetOption("landscape",num_options,options))!=NULL) + { + if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")) + { + tempOrientation = 4; + } + } if(tempOrientation>0) { if(tempOrientation==4||tempOrientation==5) @@ -721,35 +736,78 @@ main(int argc, /* I - Number of command-line arguments */ float temp = pw; pw = ph; ph = temp; + flag = 4; } } if(tempOrientation==0) { - float ratio = ph/pw; - if(h/w < ratio) + if(min(pw,w)*min(ph,h)pw) + { + final_w = pw; + } + if(h>ph) + { + final_h = ph; + } + if((fabs(final_w-w)>0.5*w)||(fabs(final_h-h)>0.5*h)) + { + fprintf(stderr,"[DEBUG]: Ignoring crop-to-fit option!\n"); + cropfit=0; + } + else{ + float posw=(w-final_w)/2,posh=(h-final_h)/2; + posw = (1+XPosition)*posw; + posh = (1-YPosition)*posh; + cups_image_t *img2 = cupsImageCrop(img,posw,posh,final_w,final_h); + cupsImageClose(img); + img = img2; + if(flag==4) + { + PageBottom+=(PageTop-PageBottom-final_w)/2; + PageTop = PageBottom+final_w; + PageLeft +=(PageRight-PageLeft-final_h)/2; + PageRight = PageLeft+final_h; + } + else{ + PageBottom+=(PageTop-PageBottom-final_h)/2; + PageTop = PageBottom+final_h; + PageLeft +=(PageRight-PageLeft-final_w)/2; + PageRight = PageLeft+final_w; + } + if(PageBottom<0) PageBottom = 0; + if(PageLeft<0) PageLeft = 0; + } + } } } if (argc == 6) diff --git a/filter/pdftopdf/pdftopdf.cc b/filter/pdftopdf/pdftopdf.cc index f2d9b37c9..bf29ec0f6 100644 --- a/filter/pdftopdf/pdftopdf.cc +++ b/filter/pdftopdf/pdftopdf.cc @@ -331,6 +331,21 @@ void getParameters(ppd_file_t *ppd,int num_options,cups_option_t *options,Proces param.fillprint=true; } } + else if((val = cupsGetOption("fill",num_options,options))!=0) { + if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")) + { + param.fillprint = true; + } + } + /* + * crop-to-fit + */ + if((val = cupsGetOption("crop-to-fit",num_options,options))!= NULL){ + if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")) + { + param.cropfit=1; + } + } if (ppd && (ppd->landscape < 0)) { // direction the printer rotates landscape (90 or -90) param.normal_landscape=ROT_270; diff --git a/filter/pdftopdf/pdftopdf_processor.cc b/filter/pdftopdf/pdftopdf_processor.cc index e6d4e142b..7f62b4f16 100644 --- a/filter/pdftopdf/pdftopdf_processor.cc +++ b/filter/pdftopdf/pdftopdf_processor.cc @@ -175,12 +175,12 @@ bool processPDFTOPDF(PDFTOPDF_Processor &proc,ProcessingParameters ¶m) // {{ } const int numPages=std::max(shuffle.size(),pages.size()); - if(param.fillprint){ - fprintf(stderr,"Cropping input pdf and Enabling fitplot.%d\n"); - for(int i=0;i page = pages[i]; - Rotation currRot = page->crop(param.page,param.orientation,param.xpos,param.ypos); + Rotation currRot = page->crop(param.page,param.orientation,param.xpos,param.ypos,!param.cropfit); } param.fitplot = 1; } @@ -332,7 +332,20 @@ bool processPDFTOPDF(PDFTOPDF_Processor &proc,ProcessingParameters ¶m) // {{ if (!param.fitplot) { curpage->add_subpage(page,pgedit.xpos+xpos,pgedit.ypos+ypos,pgedit.scale,&rect); } else { - curpage->add_subpage(page,pgedit.xpos+xpos,pgedit.ypos+ypos,pgedit.scale); + if(param.cropfit){ + double xpos2 = (param.page.right-param.page.left-(page->getRect().width))/2; + double ypos2 = (param.page.top-param.page.bottom-(page->getRect().height))/2; + if(param.orientation==ROT_270||param.orientation==ROT_90) + { + xpos2 = (param.page.right-param.page.left-(page->getRect().height))/2; + ypos2 = (param.page.top-param.page.bottom-(page->getRect().width))/2; + curpage->add_subpage(page,ypos2+param.page.bottom,xpos2+param.page.left,1); + }else{ + curpage->add_subpage(page,xpos2+param.page.left,ypos2+param.page.bottom,1); + } + } + else + curpage->add_subpage(page,pgedit.xpos+xpos,pgedit.ypos+ypos,pgedit.scale); } #ifdef DEBUG diff --git a/filter/pdftopdf/pdftopdf_processor.h b/filter/pdftopdf/pdftopdf_processor.h index a5128a691..d71fc16af 100644 --- a/filter/pdftopdf/pdftopdf_processor.h +++ b/filter/pdftopdf/pdftopdf_processor.h @@ -15,6 +15,7 @@ ProcessingParameters() user(0),title(0), fitplot(false), fillprint(false), //print-scaling = fill + cropfit(false), orientation(ROT_0),normal_landscape(ROT_270), paper_is_landscape(false), duplex(false), @@ -56,6 +57,7 @@ ProcessingParameters() const char *user, *title; // will stay around bool fitplot; bool fillprint; //print-scaling = fill + bool cropfit; // -o crop-to-fit PageRect page; Rotation orientation,normal_landscape; // normal_landscape (i.e. default direction) is e.g. needed for number-up=2 bool paper_is_landscape; @@ -108,7 +110,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) =0; + virtual Rotation crop(const PageRect &cropRect,Rotation orientation,Position xpos,Position ypos,bool scale) =0; virtual void add_subpage(const std::shared_ptr &sub,float xpos,float ypos,float scale,const PageRect *crop=NULL) =0; virtual void mirror() =0; virtual void rotate(Rotation rot) =0; diff --git a/filter/pdftopdf/qpdf_pdftopdf_processor.cc b/filter/pdftopdf/qpdf_pdftopdf_processor.cc index a136edf44..0761a4240 100644 --- a/filter/pdftopdf/qpdf_pdftopdf_processor.cc +++ b/filter/pdftopdf/qpdf_pdftopdf_processor.cc @@ -174,8 +174,9 @@ void QPDF_PDFTOPDF_PageHandle::add_border_rect(const PageRect &_rect,BorderType /* * This crop function is written for print-scaling=fill option. * 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) +Rotation QPDF_PDFTOPDF_PageHandle::crop(const PageRect &cropRect,Rotation orientation,Position xpos,Position ypos,bool scale) { page.assertInitialized(); if(orientation==ROT_0||orientation==ROT_180) @@ -195,16 +196,23 @@ Rotation QPDF_PDFTOPDF_PageHandle::crop(const PageRect &cropRect,Rotation orient { std::swap(pageHeight,pageWidth); } - if(width*pageHeight/pageWidth<=height) + if(scale) { - final_w = width; - final_h = width*pageHeight/pageWidth; + if(width*pageHeight/pageWidth<=height) + { + final_w = width; + final_h = width*pageHeight/pageWidth; + } + else{ + final_w = height*pageWidth/pageHeight; + final_h = height; + } } else{ - final_w = height*pageWidth/pageHeight; - final_h = height; + 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); double posw = (width-final_w)/2, posh = (height-final_h)/2; // posw, posh : Position along width and height respectively. diff --git a/filter/pdftopdf/qpdf_pdftopdf_processor.h b/filter/pdftopdf/qpdf_pdftopdf_processor.h index a521c8624..d1394a8af 100644 --- a/filter/pdftopdf/qpdf_pdftopdf_processor.h +++ b/filter/pdftopdf/qpdf_pdftopdf_processor.h @@ -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); + virtual Rotation crop(const PageRect &cropRect,Rotation orientation,Position xpos,Position ypos,bool scale); void debug(const PageRect &rect,float xpos,float ypos); private: bool isExisting() const; -- 2.47.2