Scale PDF to Add Border for Printing Full Size Pages

PDFBOX 2.0: How can I scale large page sizes to letter?

Setting a new MediaBox size is indeed enough to push the scaled content stream inside the smaller page. Comparing the dividends of source width/height and target width/height allows me to find a suitable scaling factor to apply to both sides, maintaining aspect ratio. The resulting margins from the pages themselves look acceptable for our use so I'm not worrying about fine control now, just setting the paper to 0 margin and letting it go. SHRINK_TO_FIT in the PDFPrintable constructor doesn't seem to be doing anything, I'm not sure what circumstances it has an effect under.

public class PDPrn {
public static void main(String[] args) {
try (PDDocument pdf = PDDocument.load(new File("foo.pdf"))) {
PrinterJob job = PrinterJob.getPrinterJob();
PDPageTree tree = pdf.getDocumentCatalog().getPages();
Iterator<PDPage> iterator = tree.iterator();
while (iterator.hasNext()) {
PDPage page = iterator.next();
if (page.getMediaBox().getWidth() > 612 || page.getMediaBox().getHeight() > 792) {
float fWidth = 612f / page.getMediaBox().getWidth();
float fHeight = 792f / page.getMediaBox().getHeight();
float factor = 0f;
if (fWidth > fHeight) {
factor = fHeight;
} else {
factor = fWidth;
}
PDPageContentStream contentStream = new PDPageContentStream(pdf, page,
PDPageContentStream.AppendMode.PREPEND, false);
contentStream.transform(Matrix.getScaleInstance(factor, factor));
contentStream.close();
page.setMediaBox(PDRectangle.LETTER);
}
}
Paper paper = new Paper();
paper.setSize(612, 792);
paper.setImageableArea(0, 0, 612, 792);
PageFormat pageFormat = new PageFormat();
pageFormat.setPaper(paper);
Book book = new Book();
book.append(new PDFPrintable(pdf, Scaling.SHRINK_TO_FIT), pageFormat, pdf.getNumberOfPages());
job.setPageable(book);
try {
job.print();
} catch (PrinterException pe) {
}
pdf.close();
} catch (IOException ioe) {
}
}
}

Set PDF to print with no scaling

Scaling is controlled by the PDF application - it is not set in the file.

GhostScript (PostScript): Printer cut- off borders when scaling down from A* to A4

It sounds like your printer has a non-printable area. This is not uncommon, the paper handling needs to hold the paper while its being printed, and this can lead to some areas of the media not being printable.

If your content reaches to the edge of the media, its possible that the printer simple cannot print there, resulting in the content being cropped.

It is entirely possible to have ps2write drop the media content to a smaller size, but you can't have it (automatically) scale down and also shift the content location, because the content is fitted to the media size.

However, the FitPage mechanism doesn't look at the content, just the media size requests. So if the input requests A3 and the selected media is A4 (and fixed) then a scale factor is applied to scale the content to the required media size (and the media request for A3 is ignored).

So what you could do is leave the code you have as it is as present, but add a BeginPage or Install procedure which uses the scale operator to further reduce the size of marks on the page, and the translate operator to move the origin slightly so that the final content is centered.

Something like (example only, untested):

<<
/BeginPage {
0.95 0.95 scale
16 20 translate
}
>> setpagedevice

By the way, you do realise Ghostscript is licenced under the AGPL ?

Also, I'd very strongly recommend that you do not use the -g and -r switches, but instead simply use -dDEVICEWIDTHPOINTS and -dDEVICEHEIGHTPOINTS to alter the media size.

The -g switch works in pixels, but high level output devices (eg pdfwrite and ps2write) don't emit pixels, they write high level vector objects. However, due to differences in the PostScript and PDF graphics models, some elements do need to be rendered to images and enclosed in that fashion in the PostScript output. By setting the resolution to 300 you are fixing the resolution at which those elements (eg pages containing transparency) are rendered. I'd suggest that you don't do so, unless you are working in a very tightly controlled workflow and know the resolution of the final output.

By using the DEVICEHEIGHTPOINTS and DEVICEWIDTHPOINTS switches you can control the media size without reference to the resolution. Note that in PostScript (and PDF) 1 point = 1/72 inch.

Scale HTML proportionally to fit exactly to PDF A4 size

Your background image is not exactly high-res, this won't look great in print.

I don't know wkhtmltopdf itself, but your body already has absolute dimensions set (in inches). This is probably the problem. Your body has a max size, the content has an absolute size too (given due to the background image pixel dimensions).

This is not a good starting point for html-to-print transformaions, and PDF is essentially print.

what to do (intermediate)

  • remove any size restrictions from body
  • wkhtml... has a switch called zoom, 1.5 should be an appropriate value to fill the page
  • use page-size a4

what to do (the "right" way)

  • remove size restrictions from body
  • build the background borders (the black ones) with html elements and css styling
    • refrain from defining "width" rules for those. You will only have to define a "width" once, all other widths should be set to "auto".
    • heights will prove troublesome, because divs are only as high as their content requires. But setting height: 100% does not respect border and margin sizes.
  • that yellow cross could be designed in css too, or a much higher resolution png/jpeg
  • Use only "real" dimensions. That means do not use pixels, use points, inches, or mm. You can use % values, but make sure those are % values of real dimensions (that means that at some point a parent element has a real dimension)

Scale image in page by adding margins to PDF with Ghostscript

You can look at the code presented in my answer here. That shows you how to rescale the content of a PDF file to a different media size, and how to reposition the scaled content on the nominal output medium.

I'm rather surprised that -c "<>setpagedevice" -f doesn't simply produce an error, since that's not valid PostScript.

[edit]

OK so you either need to do two passes or do the calculation of the scale yourself.

In the two pass model you first apply the scaling, which will get you a PDF file where the content still fills the page, but the page has been resized to the smaller dimensions. You then run it with the translation and the desired final media size, but don't set FitPage.

To do the scaling yourself you would need to add the scale to the BeginPage command instead of having Ghostscript do it for you. That means you are going to have to calculate the scale factors yourself.

The parameter to the setpagedevice operator would look something like :

<</BeginPage {0.5 0.5 scale 200 0 translate}>> setpagedevice

That will scale the content down by 50% in each direction, and move the origin by 100 points to the right. Obviously the translate values will depend on the scale factor and the size of the original and scaled media. I would try this to check it, but you haven't supplied an example PDF file to test.

iTextSharp Scaling image to be full-page

If you're determined to do it empirically, then take print a page with your code as is that scales to page border such that the image would paint black in the first half inch of margin, if it could go to the edge. Measure the distance from each edge to black in inches and divide each by 72.0.

Let's name them: lm, rm, tm, bm (left right top bottom margins.

Dim pageWidth = document.PageSize.Width - (lm + rm);
Dim pageHeight = document.PageSize.Height - (bm + tm);
Content.SetAbsolutePosition(lm, bm);
Content.ScaleToFit(pageWidth, pageHeight);
Document.Add(Content)


Related Topics



Leave a reply



Submit