I am trying to scale a PDF which is for example just small of A4 size up to A4.
This works fine with portrait documents. The document is scaled up correctly and then padding is added to the top.
On landscape documents padding is not added though. Therefor the document will end up being the correct height for A4 but then not wide enough, as padding is not added on the document side (as I hoped).
This is what I use to have it working for A4 portrait documents:
gs \
-sOutputFile=output.pdf \
-sDEVICE=pdfwrite \
-sPAPERSIZE=a4 \
-dCompatibilityLevel=1.4 \
-dNOPAUSE \
-dBATCH \
-dPDFFitPage \
input.pdf
You should add the -dFIXEDMEDIA
switch:
gs \
-o output.pdf \
-sDEVICE=pdfwrite \
-sPAPERSIZE=a4 \
-dFIXEDMEDIA \
-dPDFFitPage \
-dCompatibilityLevel=1.4 \
input.pdf
-dFIXEDMEDIA
is always required if you need to force a specific paper/page/media size and ignore the paper/page/media size specified in the document. Because PDF always has a paper/page/media size defined (PostScript might have, or might not have...).
(My -o ...
is shorter and saves one from adding -dBATCH -dNOPAUSE
-- but works only for more recent versions of Ghostscript.)
Your command doesn't do any scaling at all, it just takes a PDF file and converts it into a PDF file.
I'd suggest you try adding -dPDFFitPage which will scale the page in the PDF file to match the current page size (as specified by -sPAPERSIZE in this case).
This is usually intended to work with printers which have a defined paper size, and so may not work well with the pdfwrite device which doesn't have a fixed page size, but its worht a try.
It seems that the size of the output can be (best) forced by specifying the size in points and not using -dPDFFitPage. I was getting fractional point sizes, which was bad. The following is for A5 printing using a print on demand service. "Real" A5 is 420x595 points. I found that using -sPAPERSIZE=a5 gave fractional point page sizes, but that might have been because the original was wonky.
gs \
-o output.pdf \
-sDEVICE=pdfwrite \
-dDEVICEWIDTHPOINTS=419 -dDEVICEHEIGHTPOINTS=595 \
-dFIXEDMEDIA \
-dCompatibilityLevel=1.4 \
input.pdf
In order to test this, I found that using PDFshuffler I was able to export individual pages, then with pdfinfo I was able to get the precise size of those pages. This confirmed that using device parameters explicitly helped.
First, thanks for everyone that posted here.
I have this little script called pdfScale which absorbed parts of the answers posted here. So I decided to post back my 2 cents. I am using a bit of a mix of Kurt's and Tim's answers. More similar to Tim's though. I have played with this for a few days and here is my partial conclusion on the methods posted here:
Set Paper Size by Name with -sPAPERSIZE
- Easy to just pass the paper name (Eg. a4)
- May not produce 100% accurate points size
- May Flip Landscape <> Portrait
Set paper size in PS-points -dDEVICEWIDTHPOINTS
, -dDEVICEHEIGHTPOINTS
- Makes sure you get the size you want in points
- You can Flip WIDTH <> HEIGHT yourself
- You need to know the sizes in Points
- Not so easy to script around it, as you will need the new page size in points and would also need the source's page sizes if you want to detect landscape/portrait.
- You can set custom defined papers as well (any size you want really).
- I was using
-dDEVICEWIDTH
, -dDEVICEHEIGHT
instead of the longer, points version, but they both seem to do the same thing (both get points).
Because my bash script is already capable of getting source page sizes and I liked the idea to be able to set custom page sizes, I decided to focus on setting the page size in points. I had also already included the GS Paper Sizes in my script (with names and sizes). So getting that info was also easy.
Using -dFIXEDMEDIA
seems to be a must on both cases, as pointed out before.
So this is how my approach went (in a scripted way)
- Get Source PDF page sizes (For Flip Detection)
- Get the target's page size in points (Eg. A4 > 595x842)
- Check they have the same orientation or Flip Target if necessary
- Run GS with points or flipped points
When I was trying to fix the auto-rotation problem, I found this other Kurt response.
This is about using -dAutoRotatePages
. Just copying a part of his answer here:
-dAutoRotatePages=/None
-- retains orientation of each page;
-dAutoRotatePages=/All
-- rotates all pages (or none) depending on a kind of "majority decision";
-dAutoRotatePages=/PageByPage
-- auto-rotates pages individually.
My script defaults to PageByPage
but that is adjustable. It worked well in my tests. Using -dAutoRotatePages
also seems to reduce the need for pre-flipping the page size, even though it is not the same thing. I kept both options.
My little app was originally created to scale PDFs (without changing the page size). Then I added now the functionality to do one, the other or both. I still could not do it all in a single GS call though.
This is what I am calling for resizing, changing the variables to real values. This is for A4 Portrait size with PageByPage
auto-rotation:
gs \
-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dSAFER \
-dCompatibilityLevel="1.5" -dPDFSETTINGS="/printer" \
-dColorConversionStrategy=/LeaveColorUnchanged \
-dSubsetFonts=true -dEmbedAllFonts=true \
-dDEVICEWIDTHPOINTS=595 -dDEVICEHEIGHTPOINTS=842 \
-dAutoRotatePages='/PageByPage' \
-dFIXEDMEDIA -dPDFFitPage \
-sOutputFile='../myOutputFile.pdf' \
-f '../input.pdf'
Please note that I am also using -dFIXEDMEDIA
AND -dPDFFitPage
. Because this fits-to-page, the other part of my script may be handy to scale the contents inside the PDF after resizing (specially if the proportion of the PDF changed a lot). And that is one of the reasons I always run the scaling after resizing in my script (in mixed mode).
About the fraction problems when using the Paper Name, I had that happening to me before I rounded the conversions from mm/inches to points. After I started rounding them, they seem to always be the one needed. Seems weird that GS would floor those values though.
So my conclusion is that the hard part is to find a solution that works across the board on different documents with different sizes and orientations. I am still not sure I am using the proper solution. But by letting the user change the Flip Detection and GS Auto-Rotation I hope to have a solution for at least most cases.
I have also rebuilt most of the code in the process and it is pretty easy to read now. May be useful to check it if you want to automate such a task yourself. Also useful to just scale/resize PDFs as well of course:
https://github.com/tavinus/pdfScale
PS: pdfScale has its origins on this StackOverflow thread.
It is a shame that the features of pstops, a very useful package for
scaling and combining pages of postscript, doesn't seem to be available
for pdfs. There is a program called pdftopdf, but it does (as far as I
can see) do the same things as pstops.
You can make a ps file (I print to file in evince), use pstops, and
then ps2pdf, but that is quite clumsy.