ba45c58361
Resolves: RHEL-70015
481 lines
16 KiB
Diff
481 lines
16 KiB
Diff
From 207314fc3dbcfde829f5d0082c6a23ad695d34b9 Mon Sep 17 00:00:00 2001
|
|
From: Till Kamppeter <till.kamppeter@gmail.com>
|
|
Date: Tue, 1 Feb 2022 23:00:46 -0300
|
|
Subject: [PATCH] pdftopdf: Fixed print-scaling and N-up for asymmetric margins
|
|
and files with differently-sized pages
|
|
|
|
(manually backported commit 4aaf23aae3695348532e295859f001704a33ebad
|
|
and commit 31dfcae961ca737b7166cd6a3e7d4a30cd19f9e8)
|
|
---
|
|
NEWS | 8 +
|
|
filter/pdftopdf/pdftopdf_processor.cc | 362 ++++++++++-----------
|
|
filter/pdftopdf/qpdf_pdftopdf_processor.cc | 9 +-
|
|
3 files changed, 189 insertions(+), 190 deletions(-)
|
|
|
|
diff --git a/filter/pdftopdf/pdftopdf_processor.cc b/filter/pdftopdf/pdftopdf_processor.cc
|
|
index 6d2d32ff5..e297a246e 100644
|
|
--- a/filter/pdftopdf/pdftopdf_processor.cc
|
|
+++ b/filter/pdftopdf/pdftopdf_processor.cc
|
|
@@ -175,31 +175,46 @@ bool processPDFTOPDF(PDFTOPDF_Processor &proc,ProcessingParameters ¶m) // {{
|
|
}
|
|
const int numPages=std::max(shuffle.size(),pages.size());
|
|
|
|
+ fprintf(stderr, "DEBUG: pdftopdf: \"print-scaling\" IPP attribute: %s\n",
|
|
+ (param.autoprint ? "auto" :
|
|
+ (param.autofit ? "auto-fit" :
|
|
+ (param.fitplot ? "fit" :
|
|
+ (param.fillprint ? "fill" :
|
|
+ (param.cropfit ? "none" :
|
|
+ "Not defined, should never happen"))))));
|
|
+
|
|
if(param.autoprint||param.autofit){
|
|
bool margin_defined = true;
|
|
bool document_large = false;
|
|
int pw = param.page.right-param.page.left;
|
|
int ph = param.page.top-param.page.bottom;
|
|
- int w=0,h=0;
|
|
- Rotation tempRot=param.orientation;
|
|
- PageRect r= pages[0]->getRect();
|
|
- w = r.width;
|
|
- h = r.height;
|
|
|
|
- if(tempRot==ROT_90||tempRot==ROT_270)
|
|
+ if ((param.page.width == pw) && (param.page.height == ph))
|
|
+ margin_defined = false;
|
|
+
|
|
+ for (int i = 0; i < (int)pages.size(); i ++)
|
|
{
|
|
- std::swap(w,h);
|
|
+ PageRect r = pages[i]->getRect();
|
|
+ int w = r.width;
|
|
+ int h = r.height;
|
|
+ if ((w > param.page.width || h > param.page.height) &&
|
|
+ (h > param.page.width || w > param.page.height))
|
|
+ {
|
|
+ fprintf(stderr,
|
|
+ "DEBUG: pdftopdf: Page %d too large for output page size, scaling pages to fit.\n",
|
|
+ i + 1);
|
|
+ document_large = true;
|
|
+ }
|
|
}
|
|
- if(w>=pw||h>=ph)
|
|
+ if (param.fidelity)
|
|
+ fprintf(stderr,
|
|
+ "DEBUG: pdftopdf: \"ipp-attribute-fidelity\" IPP attribute is set, scaling pages to fit.\n");
|
|
+
|
|
+ if (param.autoprint)
|
|
{
|
|
- document_large = true;
|
|
- }
|
|
- if((param.page.width==pw)&&
|
|
- (param.page.height==ph))
|
|
- margin_defined = false;
|
|
- if(param.autoprint){
|
|
- if(param.fidelity||document_large) {
|
|
- if(margin_defined)
|
|
+ if (param.fidelity || document_large)
|
|
+ {
|
|
+ if (margin_defined)
|
|
param.fitplot = true;
|
|
else
|
|
param.fillprint = true;
|
|
@@ -215,204 +230,177 @@ bool processPDFTOPDF(PDFTOPDF_Processor &proc,ProcessingParameters ¶m) // {{
|
|
}
|
|
}
|
|
|
|
+ fprintf(stderr, "DEBUG: pdftopdf: Print scaling mode: %s\n",
|
|
+ (param.fitplot ?
|
|
+ "Scale to fit printable area" :
|
|
+ (param.fillprint ?
|
|
+ "Scale to fill page and crop" :
|
|
+ (param.cropfit ?
|
|
+ "Do not scale, center, crop if needed" :
|
|
+ "Not defined, should never happen"))));
|
|
+
|
|
+ // In Crop mode we do not scale the original document, it should keep the
|
|
+ // exact same size. With N-Up it should be scaled to fit exacly the halves,
|
|
+ // quarters, ... of the sheet, regardless of unprintable margins.
|
|
+ // Therefore we remove the unprintable margins to do all the math without
|
|
+ // them.
|
|
+ if (param.cropfit)
|
|
+ {
|
|
+ param.page.left = 0;
|
|
+ param.page.bottom = 0;
|
|
+ param.page.right = param.page.width;
|
|
+ param.page.top = param.page.height;
|
|
+ }
|
|
+
|
|
if(param.fillprint||param.cropfit){
|
|
- fprintf(stderr,"[DEBUG]: Cropping input pdf and Enabling fitplot.\n");
|
|
- if(param.noOrientation&&pages.size())
|
|
- {
|
|
- bool land = pages[0]->is_landscape(param.orientation);
|
|
- if(land)
|
|
- param.orientation = param.normal_landscape;
|
|
- }
|
|
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);
|
|
+ Rotation orientation = param.orientation;
|
|
+ if (param.noOrientation &&
|
|
+ page->is_landscape(param.orientation))
|
|
+ orientation = param.normal_landscape;
|
|
+ page->crop(param.page, orientation, param.xpos, param.ypos,
|
|
+ !param.cropfit);
|
|
}
|
|
- param.fitplot = 1;
|
|
+ if (param.fillprint)
|
|
+ param.fitplot = true;
|
|
}
|
|
|
|
std::shared_ptr<PDFTOPDF_PageHandle> curpage;
|
|
int outputpage=0;
|
|
int outputno=0;
|
|
|
|
- if ((param.nup.nupX==1)&&(param.nup.nupY==1)&&(!param.fitplot)) {
|
|
- // TODO? fitplot also without xobject?
|
|
- /*
|
|
- param.nup.width=param.page.width;
|
|
- param.nup.height=param.page.height;
|
|
- */
|
|
+ if ((param.nup.nupX == 1) && (param.nup.nupY == 1) && !param.fitplot)
|
|
+ {
|
|
+ param.nup.width = param.page.width;
|
|
+ param.nup.height = param.page.height;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ param.nup.width = param.page.right - param.page.left;
|
|
+ param.nup.height = param.page.top - param.page.bottom;
|
|
+ }
|
|
|
|
- for (int iA=0;iA<numPages;iA++) {
|
|
- if (!param.withPage(iA+1)) {
|
|
- continue;
|
|
- }
|
|
+ if ((param.orientation == ROT_90) || (param.orientation == ROT_270))
|
|
+ {
|
|
+ std::swap(param.nup.nupX, param.nup.nupY);
|
|
+ param.nup.landscape = !param.nup.landscape;
|
|
+ param.orientation = param.orientation - param.normal_landscape;
|
|
+ }
|
|
|
|
- // 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);
|
|
+ double xpos = 0, ypos = 0;
|
|
+ if (param.nup.landscape)
|
|
+ {
|
|
+ // pages[iA]->rotate(param.normal_landscape);
|
|
+ param.orientation = param.orientation + param.normal_landscape;
|
|
+ // TODO? better
|
|
+ if (param.nup.nupX != 1 || param.nup.nupY != 1 || param.fitplot)
|
|
+ {
|
|
+ xpos = param.page.height - param.page.top;
|
|
+ ypos = param.page.left;
|
|
+ }
|
|
+ std::swap(param.page.width, param.page.height);
|
|
+ std::swap(param.nup.width, param.nup.height);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (param.nup.nupX != 1 || param.nup.nupY != 1 || param.fitplot)
|
|
+ {
|
|
+ xpos = param.page.left;
|
|
+ ypos = param.page.bottom; // for whole page... TODO from position...
|
|
+ }
|
|
+ }
|
|
|
|
- if (shuffle[iA]>=numOrigPages) {
|
|
- // add empty page as filler
|
|
- proc.add_page(proc.new_page(param.page.width,param.page.height),param.reverse);
|
|
+ NupState nupstate(param.nup);
|
|
+ NupPageEdit pgedit;
|
|
+ for (int iA=0;iA<numPages;iA++) {
|
|
+ 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);
|
|
+ else
|
|
+ page=pages[shuffle[iA]];
|
|
+
|
|
+ PageRect rect;
|
|
+ rect = page->getRect();
|
|
+ //rect.dump();
|
|
+
|
|
+ bool newPage=nupstate.nextPage(rect.width,rect.height,pgedit);
|
|
+ if (newPage) {
|
|
+ if ((curpage)&&(param.withPage(outputpage))) {
|
|
+ curpage->rotate(param.orientation);
|
|
+ if (param.mirror)
|
|
+ curpage->mirror();
|
|
+ // TODO? update rect? --- not needed any more
|
|
+ proc.add_page(curpage,param.reverse); // reverse -> insert at beginning
|
|
+ // Log page in /var/log/cups/page_log
|
|
outputno++;
|
|
- continue; // no border, etc.
|
|
- }
|
|
- auto page=pages[shuffle[iA]];
|
|
-
|
|
- page->rotate(param.orientation);
|
|
-
|
|
- if (param.mirror) {
|
|
- page->mirror();
|
|
- }
|
|
-
|
|
- if (!param.pageLabel.empty()) {
|
|
- page->add_label(param.page, param.pageLabel);
|
|
+ if (param.page_logging == 1)
|
|
+ fprintf(stderr, "PAGE: %d %d\n", outputno,
|
|
+ param.copies_to_be_logged);
|
|
}
|
|
-
|
|
- // place border
|
|
- if ((param.border!=BorderType::NONE)&&(iA<numOrigPages)) {
|
|
-#if 0 // would be nice, but is not possible
|
|
- PageRect rect=page->getRect();
|
|
-
|
|
- rect.left+=param.page.left;
|
|
- rect.bottom+=param.page.bottom;
|
|
- rect.top-=param.page.top;
|
|
- rect.right-=param.page.right;
|
|
- // width,height not needed for add_border_rect (FIXME?)
|
|
-
|
|
- page->add_border_rect(rect,param.border,1.0);
|
|
-#else // this is what pstops does
|
|
- page->add_border_rect(param.page,param.border,1.0);
|
|
-#endif
|
|
- }
|
|
-
|
|
- proc.add_page(page,param.reverse); // reverse -> insert at beginning
|
|
- outputno++;
|
|
+ curpage=proc.new_page(param.page.width,param.page.height);
|
|
+ outputpage++;
|
|
}
|
|
- } else {
|
|
- param.nup.width=param.page.right-param.page.left;
|
|
- param.nup.height=param.page.top-param.page.bottom;
|
|
-
|
|
- double xpos=param.page.left,
|
|
- ypos=param.page.bottom; // for whole page... TODO from position...
|
|
-
|
|
- const bool origls=param.nup.landscape;
|
|
- if ((param.orientation==ROT_90)||(param.orientation==ROT_270)) {
|
|
- std::swap(param.nup.nupX,param.nup.nupY);
|
|
- param.nup.landscape=!param.nup.landscape;
|
|
- param.orientation=param.orientation-param.normal_landscape;
|
|
- }
|
|
- if (param.nup.landscape) {
|
|
- // pages[iA]->rotate(param.normal_landscape);
|
|
- param.orientation=param.orientation+param.normal_landscape;
|
|
- // TODO? better
|
|
- xpos=param.page.bottom;
|
|
- ypos=param.page.width - param.page.right;
|
|
- std::swap(param.page.width,param.page.height);
|
|
- std::swap(param.nup.width,param.nup.height);
|
|
+ if (shuffle[iA]>=numOrigPages) {
|
|
+ continue;
|
|
}
|
|
|
|
- NupState nupstate(param.nup);
|
|
- NupPageEdit pgedit;
|
|
- for (int iA=0;iA<numPages;iA++) {
|
|
- 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);
|
|
- } else {
|
|
- page=pages[shuffle[iA]];
|
|
- }
|
|
-
|
|
- PageRect rect;
|
|
- if (param.fitplot) {
|
|
- rect=page->getRect();
|
|
- } else {
|
|
- rect.width=param.page.width;
|
|
- rect.height=param.page.height;
|
|
-
|
|
- // TODO? better
|
|
- if (origls) {
|
|
- std::swap(rect.width,rect.height);
|
|
- }
|
|
-
|
|
- rect.left=0;
|
|
- rect.bottom=0;
|
|
- rect.right=rect.width;
|
|
- rect.top=rect.height;
|
|
- }
|
|
- // rect.dump();
|
|
-
|
|
- bool newPage=nupstate.nextPage(rect.width,rect.height,pgedit);
|
|
- if (newPage) {
|
|
- if ((curpage)&&(param.withPage(outputpage))) {
|
|
- curpage->rotate(param.orientation);
|
|
- if (param.mirror) {
|
|
- curpage->mirror();
|
|
- // TODO? update rect? --- not needed any more
|
|
- }
|
|
- proc.add_page(curpage,param.reverse); // reverse -> insert at beginning
|
|
- // 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);
|
|
- }
|
|
- curpage=proc.new_page(param.page.width,param.page.height);
|
|
- outputpage++;
|
|
- }
|
|
- if (shuffle[iA]>=numOrigPages) {
|
|
- continue;
|
|
- }
|
|
-
|
|
- if (param.border!=BorderType::NONE) {
|
|
- // TODO FIXME... border gets cutted away, if orignal page had wrong size
|
|
- // page->"uncrop"(rect); // page->setMedia()
|
|
- // Note: currently "fixed" in add_subpage(...&rect);
|
|
- page->add_border_rect(rect,param.border,1.0/pgedit.scale);
|
|
- }
|
|
+ if (param.border!=BorderType::NONE) {
|
|
+ // TODO FIXME... border gets cutted away, if orignal page had wrong size
|
|
+ // page->"uncrop"(rect); // page->setMedia()
|
|
+ // Note: currently "fixed" in add_subpage(...&rect);
|
|
+ page->add_border_rect(rect,param.border,1.0/pgedit.scale);
|
|
+ }
|
|
|
|
- if (!param.pageLabel.empty()) {
|
|
- page->add_label(param.page, param.pageLabel);
|
|
- }
|
|
+ if (!param.pageLabel.empty()) {
|
|
+ page->add_label(param.page, param.pageLabel);
|
|
+ }
|
|
|
|
- if (!param.fitplot) {
|
|
- curpage->add_subpage(page,pgedit.xpos+xpos,pgedit.ypos+ypos,pgedit.scale,&rect);
|
|
- } else {
|
|
- 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);
|
|
+ if (param.cropfit)
|
|
+ {
|
|
+ if ((param.nup.nupX == 1) && (param.nup.nupY == 1))
|
|
+ {
|
|
+ double xpos2, ypos2;
|
|
+ if (param.orientation == ROT_270 || param.orientation == ROT_90)
|
|
+ {
|
|
+ xpos2 = (param.page.width - (page->getRect().height)) / 2;
|
|
+ ypos2 = (param.page.height - (page->getRect().width)) / 2;
|
|
+ curpage->add_subpage(page, ypos2 + xpos, xpos2 + ypos, 1);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ xpos2 = (param.page.width - (page->getRect().width)) / 2;
|
|
+ ypos2 = (param.page.height - (page->getRect().height)) / 2;
|
|
+ curpage->add_subpage(page, xpos2 + xpos, ypos2 + ypos, 1);
|
|
+ }
|
|
}
|
|
+ else
|
|
+ curpage->add_subpage(page,pgedit.xpos+xpos,pgedit.ypos+ypos,pgedit.scale);
|
|
+ }
|
|
+ else
|
|
+ curpage->add_subpage(page, pgedit.xpos + xpos, pgedit.ypos + ypos,
|
|
+ pgedit.scale);
|
|
|
|
#ifdef DEBUG
|
|
- if (auto dbg=dynamic_cast<QPDF_PDFTOPDF_PageHandle *>(curpage.get())) {
|
|
- // dbg->debug(pgedit.sub,xpos,ypos);
|
|
- }
|
|
+ if (auto dbg=dynamic_cast<QPDF_PDFTOPDF_PageHandle *>(curpage.get())) {
|
|
+ dbg->debug(pgedit.sub,xpos,ypos);
|
|
+ }
|
|
#endif
|
|
|
|
- // pgedit.dump();
|
|
- }
|
|
- if ((curpage)&&(param.withPage(outputpage))) {
|
|
- curpage->rotate(param.orientation);
|
|
- if (param.mirror) {
|
|
- curpage->mirror();
|
|
- }
|
|
- proc.add_page(curpage,param.reverse); // reverse -> insert at beginning
|
|
- // 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);
|
|
+ // pgedit.dump();
|
|
+ }
|
|
+ if ((curpage)&&(param.withPage(outputpage))) {
|
|
+ curpage->rotate(param.orientation);
|
|
+ if (param.mirror) {
|
|
+ curpage->mirror();
|
|
}
|
|
+ proc.add_page(curpage,param.reverse); // reverse -> insert at beginning
|
|
+ // 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 ((param.evenDuplex || !param.oddPages) && (outputno & 1)) {
|
|
diff --git a/filter/pdftopdf/qpdf_pdftopdf_processor.cc b/filter/pdftopdf/qpdf_pdftopdf_processor.cc
|
|
index d06ca5f77..621c76880 100644
|
|
--- a/filter/pdftopdf/qpdf_pdftopdf_processor.cc
|
|
+++ b/filter/pdftopdf/qpdf_pdftopdf_processor.cc
|
|
@@ -179,6 +179,7 @@ void QPDF_PDFTOPDF_PageHandle::add_border_rect(const PageRect &_rect,BorderType
|
|
Rotation QPDF_PDFTOPDF_PageHandle::crop(const PageRect &cropRect,Rotation orientation,Position xpos,Position ypos,bool scale)
|
|
{
|
|
page.assertInitialized();
|
|
+ Rotation save_rotate = getRotate(page);
|
|
if(orientation==ROT_0||orientation==ROT_180)
|
|
page.replaceOrRemoveKey("/Rotate",makeRotate(ROT_90));
|
|
else
|
|
@@ -209,8 +210,8 @@ Rotation QPDF_PDFTOPDF_PageHandle::crop(const PageRect &cropRect,Rotation orient
|
|
}
|
|
}
|
|
else{
|
|
- final_w = std::min(width,pageWidth);
|
|
- final_h = std::min(height,pageHeight);
|
|
+ final_w = pageWidth;
|
|
+ final_h = pageHeight;
|
|
}
|
|
fprintf(stderr,"After Cropping: %lf %lf %lf %lf\n",width,height,final_w,final_h);
|
|
double posw = (width-final_w)/2,
|
|
@@ -235,13 +236,14 @@ Rotation QPDF_PDFTOPDF_PageHandle::crop(const PageRect &cropRect,Rotation orient
|
|
//Cropping.
|
|
// TODO: Borders are covered by the image. buffer space?
|
|
page.replaceKey("/TrimBox",makeBox(currpage.left,currpage.bottom,currpage.right,currpage.top));
|
|
- page.replaceOrRemoveKey("/Rotate",makeRotate(ROT_0));
|
|
+ page.replaceOrRemoveKey("/Rotate",makeRotate(save_rotate));
|
|
return getRotate(page);
|
|
}
|
|
|
|
bool QPDF_PDFTOPDF_PageHandle::is_landscape(Rotation orientation)
|
|
{
|
|
page.assertInitialized();
|
|
+ Rotation save_rotate = getRotate(page);
|
|
if(orientation==ROT_0||orientation==ROT_180)
|
|
page.replaceOrRemoveKey("/Rotate",makeRotate(ROT_90));
|
|
else
|
|
@@ -250,6 +252,7 @@ bool QPDF_PDFTOPDF_PageHandle::is_landscape(Rotation orientation)
|
|
PageRect currpage= getBoxAsRect(getTrimBox(page));
|
|
double width = currpage.right-currpage.left;
|
|
double height = currpage.top-currpage.bottom;
|
|
+ page.replaceOrRemoveKey("/Rotate",makeRotate(save_rotate));
|
|
if(width>height)
|
|
return true;
|
|
return false;
|
|
--
|
|
2.47.1
|
|
|