Reputation:
I've been struggling with this for awhile so thought I would post this for any gurus who might be able to knock out a solution.
I have a PDF document that I'd like to copy and when I copy it I would like to resize the pages to custom size. For example, the original document has a page size of 8 1/2 x 16. The new document needs to be 8 1/2 by 22. The 8 1/2 in the new doc comes from the width of the original; the 22 is fixed (constant). What complicates the issue is that the new doc needs to have the old doc contents centered on the page. So in the new document it would need to have margins of 3 inches top, 3 inches bottom so that the original 16 inches was centered. Width doesn't matter, just the height needs to be centered.
Created the following solution which works. Posting back to the community in the hopes it may help someone. Solution is in VB.NET.
To use call resizeAndRotateDocument with 2 booleans. "rotate" - rotate each page 90 degrees - true, false. and "resize" - resizes the page to a 22 inch height with margins added to top/bottome to center page - true/false. And also 2 strings: the name of the input pdf file to process and the name of the output pdf file to create.
Private Sub AdjustMediaBoxSize(ByRef mediaBoxSize As PdfArray, ByVal rotationIsPresent As Boolean)
Const Fixed_22_Inch_Page As Integer = 22 * 72
Dim ll_x, ll_y, ur_x, ur_y As Integer
Dim heightDiff, heightAdjustment As Integer
Dim new_ll_x, new_ll_y, new_ur_x, new_ur_y As Integer
' Read current coordinates of the Mediabox
ll_x = mediaBoxSize(0).ToString
ll_y = mediaBoxSize(1).ToString
ur_x = mediaBoxSize(2).ToString
ur_y = mediaBoxSize(3).ToString
' Figure out the height difference and the adjustment factor.
If rotationIsPresent = True Then
heightDiff = Fixed_22_Inch_Page - ur_x
Else
heightDiff = Fixed_22_Inch_Page - ur_y
End If
' adjustment needed to top and to bottom
heightAdjustment = heightDiff / 2
' Apply the adjustments; only use the ones we need.
new_ll_x = ll_x - heightAdjustment
new_ur_x = ur_x + heightAdjustment
new_ll_y = ll_y - heightAdjustment
new_ur_y = ur_y + heightAdjustment
If rotationIsPresent = True Then
mediaBoxSize(0) = New iTextSharp.text.pdf.PdfNumber(new_ll_x)
mediaBoxSize(2) = New iTextSharp.text.pdf.PdfNumber(new_ur_x)
Else
' Make the adjustment. Value is passed back by reference.
mediaBoxSize(1) = New iTextSharp.text.pdf.PdfNumber(new_ll_y)
mediaBoxSize(3) = New iTextSharp.text.pdf.PdfNumber(new_ur_y)
End If
End Sub
Private Sub resizeAndRotateDocument(ByVal rotate As Boolean, ByVal resize As Boolean, ByVal inPDF As String, ByVal outPDF As String)
Const desiredRot As Integer = 90
Dim reader As New PdfReader(inPDF)
Dim pageCount As Integer = reader.NumberOfPages
Dim pageDict As PdfDictionary
Dim mediabox As New PdfArray
Dim cropbox As New PdfArray
For i As Integer = 1 To pageCount
pageDict = reader.GetPageN(i)
' Rotation is hard coded to 90 degrees.
If rotate = True Then
pageDict.Put(PdfName.ROTATE, New PdfNumber(desiredRot))
End If
If resize = True Then
' Read the current mediabox dimensions.
' Then adjust the size to scale up to 22 inches adjusting for rotation if necessary.
' Finally, write the updated mediabox back to the dictionary -> to the reader.
mediabox = pageDict.GetAsArray(PdfName.MEDIABOX)
AdjustMediaBoxSize(mediabox, rotate)
pageDict.Put(PdfName.MEDIABOX, mediabox)
End If
' Since the PDFs are created in-house, they should NEVER contain a cropbox.
cropbox = pageDict.GetAsArray(PdfName.CROPBOX)
If cropbox IsNot Nothing Then
MsgBox("Error ... found a valid cropbox !!!")
End If
Next
' Use the stamper to create and write the pdf output file.
Dim pdfStamper As New PdfStamper(reader, New FileStream(outPDF, FileMode.Create))
pdfStamper.Close()
End Sub
And thanks again Bruno !
Upvotes: 0
Views: 3119
Reputation: 77528
Take a look at the RotatePages example from my book. In the ManipulatePdf()
method, I loop over the pages, I take the page dictionary, and I change the /Rotate
key to rotate the page. That's not what you need, but the principle is similar.
You need to get the /MediaBox
and /CropBox
value from the page dictionary:
PdfArray mediabox = pageDict.getAsArray(PdfName.MEDIABOX);
PdfArray cropbox = pageDict.getAsArray(PdfName.CROPBOX);
In many cases, cropbox will be null
in which case you can safely ignore it.
You have pages measuring 8 1/2 by 16 inch, so I guess mediabox will be an array that looks like this: [ 0 0 612 1152 ]
The zeros are the coordinates of the lower-left corner. The upper-right corner has the coordinate x = 612 (72 x 8.5) and y = 1152 (72 x 16).
Now you need to replace the /MediaBox entry with a similar array where you subtract 216 (72 x 3) from the second value and add 216 to the fourth. In other words: you'll end up with the following array [ 0 -216 612 1368 ]
. Replace the /MediaBox
(and the /CropBox
if present) with such an altered array the same way I replaced the /Rotate
key, and you have your sample code.
I wouldn't use absolute values if I were you, I'd subtract 216 from whatever value is present in the array you find in the page dictionary.
Disclaimer: I'm the original author of iText, as well as of the "iText in Action" books from which the rotate example was taken. I'm a Java developer; I paid other developers to port the examples from my book to C#. Please don't ask me to write out your example in C# because I've never written any C# code, only Java code. I'm sure you'll be able to write the code that meets your needs with the information given in this post.
Upvotes: 2