cups-filters/0001-pdftopdf-Fixed-print-scaling-and-N-up-for-asymmetric.patch
2024-12-12 16:45:15 +01:00

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 &param) // {{
}
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 &param) // {{
}
}
+ 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