I'm creating an application for Windows 8.1 in C#. Into Windows.Data.Pdf i've found how use PDF files in my application. But i want to know if i can split one A3 page to multiple PDF files ?
You don't want to split a page, you want to tile it.
This is explained in Chapter 6 of my book (section 6.2.3). Take a look at the TilingHero example (Java / C#). In this example, one large page (hero.pdf) is split into a PDF with several A4 pages (superman.pdf).
This is some code:
PdfReader reader = new PdfReader(resource);
Rectangle pagesize = reader.GetPageSizeWithRotation(1);
using (Document document = new Document(pagesize)) {
// step 2
PdfWriter writer = PdfWriter.GetInstance(document, ms);
// step 3
document.Open();
// step 4
PdfContentByte content = writer.DirectContent;
PdfImportedPage page = writer.GetImportedPage(reader, 1);
// adding the same page 16 times with a different offset
float x, y;
for (int i = 0; i < 16; i++) {
x = -pagesize.Width * (i % 4);
y = pagesize.Height * (i / 4 - 3);
content.AddTemplate(page, 4, 0, 0, 4, x, y);
document.NewPage();
}
}
The math is valid for an A0 page. You need to adapt it for an A3 page (meaning: the math you need is way easier to do).
You need to calculate pagesize so that it results in smaller pages, and then use something like this:
using (Document document = new Document(pagesize)) {
// step 2
PdfWriter writer = PdfWriter.GetInstance(document, ms);
// step 3
document.Open();
// step 4
PdfContentByte content = writer.DirectContent;
PdfImportedPage page = writer.GetImportedPage(reader, 1);
// adding the same page 16 times with a different offset
float x, y;
for (int i = 0; i < 16; i++) {
x = -pagesize.Width * (i % 4);
y = pagesize.Height * (i / 4 - 3);
content.AddTemplate(page, x, y); // we don't scale anymore
document.NewPage();
}
}
Related
I have pdf files in receipt format (e.g. 80x1000mm), one long page per document.
I want to create a new pdf and split the receipt into several printable A4 pages.
The receipt contains blocks (e.g. QR.Codes) which must not be cut in the middle.
So the new pages must be created based on given lengths (rectangles) (measured from the top edge). e.g.
Page 1: 0 - 272mm
Page 2: 272 - 513mm
Page 3: 513 - 783 mm
Page 4: 783 - to end
How can I split the pdf page into several pages with iText7 in c# by specifying rectangels?
looked at several examples (git TileClipped.java, C06E02_TheGoldenGateBridge_Tiles)
I have created a very simple example to play around with coordinates, AddXObjectAt, PdfCanvas AffineTransform, ConcatMatrix, Clip etc..
The example generates a 1000mm long pdf.
I have experimented with this pdf. For the beginning I just tried to cut 4 x 250mm.
Unfortunately without success.
using System;using iText.Commons;using iText.Kernel;using iText.Kernel.Colors;using iText.Kernel.Font;using iText.Kernel.Geom;using iText.Kernel.Pdf;using iText.Kernel.Pdf.Canvas;using iText.Kernel.Pdf.Xobject;using iText.Layout;using iText.Layout.Element;
namespace SplitPage
{
internal class Program
{
public const string fileReceipt = "c:\\tmp\\receipt1000mm.pdf";
public const string fileA4 = "c:\\tmp\\receiptA4.pdf";
static void Main(string[] args)
{
new Program().CreateAndSplitPdfReceipt();
}
static float mmToPt(float mm) => mm * 72.0f / 25.4f;
void CreateAndSplitPdfReceipt()
{
float recieptLength = 2834.6f; // 1000mm approx 2834.6 pt
float recieptWidth = 220f; // approx 78mm
// Create 1000mm long receipt (= 2834.6pt)
{
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(fileReceipt));
pdfDoc.SetDefaultPageSize(new PageSize(recieptWidth, recieptLength));
Document doc = new Document(pdfDoc);
for (int i = 1; i <= 250; i++)
{
float y = recieptLength - mmToPt(i * 4f); // 4mm per row * 250rows = 1000mm
var p = new Paragraph(string.Format("Row {0}: y={1:f1} y'={2}mm ", i, y, i*4));
p.SetFontSize(8);
p.SetFixedPosition(10, y, 220);
p.SetMargin(0);
doc.Add(p);
}
pdfDoc.Close();
}
// split receipt1000.pdf in 4 equal parts a 250mm
{
float chunk = recieptLength / 4f;
PdfDocument srcDoc = new PdfDocument(new PdfReader(fileReceipt));
PdfDocument pdfA4 = new PdfDocument(new PdfWriter(fileA4));
pdfA4.SetDefaultPageSize(PageSize.A4);
PdfPage srcPage = srcDoc.GetPage(1); // just one page in receipt
PdfFormXObject copyObject = srcPage.CopyAsFormXObject(pdfA4);
PdfPage pageA4;
PdfCanvas canvas;
// 1st
pageA4 = pdfA4.AddNewPage(PageSize.A4);
canvas = new PdfCanvas(pageA4);
canvas.AddXObjectAt(copyObject, 0, 3 * chunk);
// 2nd
pageA4 = pdfA4.AddNewPage(PageSize.A4);
canvas = new PdfCanvas(pageA4);
canvas.AddXObjectAt(copyObject, 0, 2 * chunk);
// 3rd
pageA4 = pdfA4.AddNewPage(PageSize.A4);
canvas = new PdfCanvas(pageA4);
canvas.AddXObjectAt(copyObject, 0, 1 * chunk);
// 4th
pageA4 = pdfA4.AddNewPage(PageSize.A4);
canvas = new PdfCanvas(pageA4);
canvas.AddXObjectAt(copyObject, 0, 0);
srcDoc.Close();
pdfA4.Close(); }}}}
My problem is obviously that I did not understand the basic operations.
I am converting a multi-paged (paginated) pdf document into a single page (non-paginated) pdf document.
I am looking to overcome the 200 inch limitation in adobe reader.
With iTextSharp.PdfReader each page is read to create a total height of the target document and find the maximum width.
The code to create the document works ok reading directly from the paginated pdf into the non-paginated pdf. Utilizing Chrome or Foxit the file opens fine. Adobe gives the 200 inch truncation when the page exceeds 200 inchs. In my test file the page height is 8.25 x 814 inches.
Changing the UserUnits to 4.07 (814/200) has Adobe show the page height as 814in but still truncates the page as well as showing the width as 33.
If the width of the target file is set to width/userunits (8.25/4.07) the only left 2 inches are shown in the target file.
The copy part of the code:
RandomAccessFileOrArray ra = new RandomAccessFileOrArray(fn);
SizeF pageSize = new SizeF(pageWidth, pageHeight);
float USERUnitNewValue = ComputeUserUnit(pageSize);
if (pageHeight > 14400f)
{
USERUnitNewValue = pageHeight / 14400f;
}
float NewPageWidth = (pageWidth <= 14400f) ? pageWidth : pageWidth* USERUnitNewValue;
float NewPageHeight = pageHeight * USERUnitNewValue;
FileInfo file1 = new FileInfo(newfn);
DirectoryInfo directory1 = file1.Directory;
if (!directory1.Exists)
directory1.Create();
iTextSharp.text.Rectangle newPagesize = new iTextSharp.text.Rectangle(pageWidth, pageHeight);
Document newPdf = new Document(newPagesize);
PdfWriter writer = PdfWriter.GetInstance(newPdf, new FileStream(newfn, FileMode.Create));
writer.PdfVersion = PdfWriter.VERSION_1_6;
if (pageHeight > 14400)
{
writer.Userunit = USERUnitNewValue;
}
newPdf.SetMargins(0f, 0f, 0f, 0f);
newPdf.Open();
PdfContentByte cb = writer.DirectContent;
float verticalPosition = pageHeight;
for (int pagenumber = 1; pagenumber <= n1; pagenumber++)
{
if (pdfReader.NumberOfPages >= pagenumber)
{
verticalPosition = verticalPosition - pdfReader.GetPageSize(pagenumber).Height;
cb.AddTemplate(writer.GetImportedPage(pdfReader, pagenumber), 0, verticalPosition);
}
else
{
break;
}
}
newPdf.Close();
How can the original file be copied into the target where both files would keep the same size if someone sends it to a printer?
Yes there is some redundancy in this code as I have been troubleshooting this for a little while now.
The key question here is a setting that would maintain the 8.25 x 814in and still allow adobe to open the file.
Thanks,
Mike
Thank you David.
After looking through Mr Lowagie's document and brief note about addTemplate.
cb.addTemplate(page, scale, 0, 0, scale, 0, 0)
The code was updated to utilize the new userunit and scaling.
Opening ok in Adobe now and reporting page length as expected
Once again the code is a little ugly still
RandomAccessFileOrArray ra = new RandomAccessFileOrArray(fn);
SizeF pageSize = GetPageSize(fn);
PdfReader pdfReader = new PdfReader(fn);
float USERUnitNewValue = ComputeUserUnit(pageSize);
int n1 = pdfReader.NumberOfPages;
if (pageSize.Height > 14400f) //14400 value is 72 pixels per inch over 200 inches. 200 inches seems to be adobe limit to a page
{ //determine the userunit to be used
USERUnitNewValue = pageSize.Height / 14400f;
}
float NewPageWidth = (pageSize.Width <= 14400f) ? pageSize.Width / USERUnitNewValue : pageSize.Width / USERUnitNewValue;
float NewPageHeight = pageSize.Height / USERUnitNewValue;
FileInfo file1 = new FileInfo(newfn);
DirectoryInfo directory1 = file1.Directory;
if (!directory1.Exists)
directory1.Create();
iTextSharp.text.Rectangle newPagesize = new iTextSharp.text.Rectangle(NewPageWidth, NewPageHeight);
Document newPdf = new Document(newPagesize);
PdfWriter writer = PdfWriter.GetInstance(newPdf, new FileStream(newfn, FileMode.Create));
writer.PdfVersion = PdfWriter.VERSION_1_6;
if (pageSize.Height > 14400)
{
writer.Userunit = USERUnitNewValue;
}
newPdf.SetMargins(0f, 0f, 0f, 0f);
newPdf.Open();
PdfContentByte cb = writer.DirectContent;
float verticalPosition = NewPageHeight;
for (int pagenumber = 1; pagenumber <= n1; pagenumber++)
{
if (pdfReader.NumberOfPages >= pagenumber)
{
/*convoluted page position. First position should be 0,0
unlike other counters this starts as page 1 so we need to subtract the
first page height away so that we start at the bottom of the previous image
* hmm seems that ths AddTemplate feature adds the pages in reverse order or
* at least the coordinate system sets 0,0 at the bottom left of the page
*/
float widthfactor = 1 / USERUnitNewValue; //Page scaling (width)
float heightfactor = 1 / USERUnitNewValue; //Page scaling (height)
//vertical position needs to take into account the new page height taking new UserUnit in affect
verticalPosition = verticalPosition - (pdfReader.GetPageSize(pagenumber).Height / USERUnitNewValue);
cb.AddTemplate(writer.GetImportedPage(pdfReader, pagenumber), heightfactor, 0, 0, widthfactor, 0, verticalPosition);
}
else
{
break;
}
}
newPdf.Close();
Thank you again for your help,
Mike
I'm working with pdfs, I'm merging them first and then creating a heading and a footer for every page of the merged pdf. I'm using one method to merge and a different one to set the header and footer.
For certain documents the header and footer overlaps with the content. I've tried to set margin for the document but it doesn't change anything.
public byte[] HeaderAndFooter(byte[] inputPdf)
{
var dest = new MemoryStream();
PdfDocument pdfDoc = new PdfDocument(new PdfReader(inputPdf.ToMemoryStream()),
new PdfWriter(dest));
Document doc = new Document(pdfDoc);
doc.SetMargins(200,200, 200, 200); /* It doesn't matter the
numbers I set in here the document remains the same...*/
numberOfPages = pdfDoc.GetNumberOfPages();
Paragraph header = new Paragraph("This is a header for every page...")
.SetFont(PdfFontFactory.CreateFont(FontConstants.HELVETICA))
.SetFontSize(10)
.SetFontColor(Color.BLACK);
for (int i = 1; i <= numberOfPages; i++)
{
var pageSize = pdfDoc.GetPage(i).GetPageSize();
float LeftMargin = 36;
float BottomMargin = 24;
float y = pageSize.GetTop() - 72;
float center = pageSize.GetWidth() / 2;
doc.ShowTextAligned(header, LeftMargin, y, i, TextAlignment.LEFT, VerticalAlignment.BOTTOM, 0);
doc.ShowTextAligned(footerL, LeftMargin, BottomMargin, i, TextAlignment.LEFT, VerticalAlignment.BOTTOM, 0);
doc.ShowTextAligned(footerC, center, BottomMargin, i, TextAlignment.CENTER, VerticalAlignment.BOTTOM, 0);
}
doc.Close();
return dest.ToArray();
}
How could I avoid the header and footer from overlapping with the content?
I'm using iTextSharp to handle pdf files. I'd like to know how I can split a page in half and make 2 different pages from the two pieces. I tried a lot but nothing seems to work right now.
First try
iTextSharp.text.Rectangle size = new iTextSharp.text.Rectangle(0, pdfReader.GetPageSize(1).Height / 2, pdfReader.GetPageSize(1).Width, 0);
Second try
iTextSharp.text.Rectangle size = pdfReader.GetPageSizeWithRotation(1);
iTextSharp.text.Document document = new iTextSharp.text.Document(size.GetRectangle(0, size.Height / 2));
And several others. The results are always the same: I have a file with just the second half of the original page.
I don't understand your code snippets, but then again: probably you don't understand them either, so let's not look at what you've written so far, and let's take a closer look at the TileInTwo example:
public void manipulatePdf(String src, String dest)
throws IOException, DocumentException {
// Creating a reader
PdfReader reader = new PdfReader(src);
int n = reader.getNumberOfPages();
// step 1
Rectangle mediabox = new Rectangle(getHalfPageSize(reader.getPageSizeWithRotation(1)));
Document document = new Document(mediabox);
// step 2
PdfWriter writer
= PdfWriter.getInstance(document, new FileOutputStream(dest));
// step 3
document.open();
// step 4
PdfContentByte content = writer.getDirectContent();
PdfImportedPage page;
int i = 1;
while (true) {
page = writer.getImportedPage(reader, i);
content.addTemplate(page, 0, -mediabox.getHeight());
document.newPage();
content.addTemplate(page, 0, 0);
if (++i > n)
break;
mediabox = new Rectangle(getHalfPageSize(reader.getPageSizeWithRotation(i)));
document.setPageSize(mediabox);
document.newPage();
}
// step 5
document.close();
reader.close();
}
public Rectangle getHalfPageSize(Rectangle pagesize) {
float width = pagesize.getWidth();
float height = pagesize.getHeight();
return new Rectangle(width, height / 2);
}
In this example, we ask the PdfReader instance for the page size of the first page and we create a new rectangle with the same width and only half the height.
We then import each page in the document, and we add it twice on different pages:
once on the odd pages with a negative y value to show the upper half of the original page,
once on the even pages with y = 0 to show the lower half of the original page.
As every page in the original document can have a different size, we may need to change the page size for every new couple of pages.
I want to add page numbers to the footer of the itextsharp pdf file.Im generating pdf from html (asp.net repeater).And Im using XMLWorkerHelper to parse the html content.I searched a lot but cant find anything useful to achive this.
You'll have to open the PDF with iTextSharp and add the page numbers yourself. I did something like this a while back, here's my function that might give you a start.
The function adds the current page to the lower left, so you might have to place it somewhere else that fits your needs.
public static byte[] AddPageNumbers(byte[] pdf)
{
MemoryStream ms = new MemoryStream();
// we create a reader for a certain document
PdfReader reader = new PdfReader(pdf);
// we retrieve the total number of pages
int n = reader.NumberOfPages;
// we retrieve the size of the first page
Rectangle psize = reader.GetPageSize(1);
// step 1: creation of a document-object
Document document = new Document(psize, 50, 50, 50, 50);
// step 2: we create a writer that listens to the document
PdfWriter writer = PdfWriter.GetInstance(document, ms);
// step 3: we open the document
document.Open();
// step 4: we add content
PdfContentByte cb = writer.DirectContent;
int p = 0;
Console.WriteLine("There are " + n + " pages in the document.");
for (int page = 1; page <= reader.NumberOfPages; page++)
{
document.NewPage();
p++;
PdfImportedPage importedPage = writer.GetImportedPage(reader, page);
cb.AddTemplate(importedPage, 0, 0);
BaseFont bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
cb.BeginText();
cb.SetFontAndSize(bf, 10);
cb.ShowTextAligned(PdfContentByte.ALIGN_LEFT, +p + "/" + n, 7, 44, 0);
cb.EndText();
}
// step 5: we close the document
document.Close();
return ms.ToArray();
}
Something like this should work:
var sourceFileList = new List<string>();
//add files to merge
int sourceIndex = 0;
PdfReader reader = new PdfReader(sourceFileList[sourceIndex]);
int sourceFilePageCount = reader.NumberOfPages;
Document doc = new Document(reader.GetPageSizeWithRotation(1));
PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(destinationFileName, FileMode.Create));
doc.Open();
PdfImportedPage page;
PdfContentByte contentByte = writer.DirectContent;
int rotation;
while (sourceIndex < sourceFileList.Count)
{
int pageIndex = 0;
while (pageIndex < sourceFilePageCount)
{
pageIndex++;
doc.SetPageSize(reader.GetPageSizeWithRotation(pageIndex));
doc.NewPage();
page = writer.GetImportedPage(reader, pageIndex);
rotation = reader.GetPageRotation(pageIndex);
if (rotation.Equals(90 | 270))
contentByte.AddTemplate(page, 0, -1f, 1f, 0, 0, reader.GetPageSizeWithRotation(pageIndex).Height);
else
contentByte.AddTemplate(page, 1f, 0, 0, 1f, 0, 0);
}
sourceIndex++;
if (sourceIndex < sourceFileList.Count)
{
reader = new PdfReader(sourceFileList[sourceIndex]);
sourceFilePageCount = reader.NumberOfPages;
}
}
doc.Close();