I'm trying to build pdfs to digitize our reporting system at my company. I've used iTextSharp and so far it looks great but my margins don't seem to be working properly. I've set the margins to a config file and the left and right margins are working great, but my paragraph seems to start about 30% down the page regardless of the top and bottom margin. Here's the code I'm using:
public int PrintPdf()
{
//Getting the path
//Path.GetFileNameWithoutExtension("Test_Doc_Print") + ".pdf");
object OutputFileName = this._path;
//Making the PDF Doc
iTextSharp.text.Document PDFReport = new iTextSharp.text.Document
(
PageSize.A4.Rotate(),
/*this._left,
this._right,
this._top,
this._bottom*/
10,
10,
10,
10
);
//Setting The Font
string fontpath = #"C:\Windows\Fonts\";
BaseFont monoFont = BaseFont.CreateFont(fontpath + "Consola.ttf", BaseFont.CP1252, BaseFont.EMBEDDED);
Font fontPDF = new Font(monoFont, this._fontSize);
// create file stream for writing the PDF
FileStream fs = new FileStream(this._path, FileMode.Create, FileAccess.ReadWrite);
//FileStream fs = new FileStream(#"c:\\Reportlocation", FileMode.Create);
// Create an FCFC scan object to convert TextToPrint page at a time
FCFCScanner page = new FCFCScanner(this._text);
// Create PDF writer and associate with file stream
//iTextSharp.text.pdf.PdfWriter writer = new iTextSharp.text.pdf.PdfWriter.GetInstance(PDFReport, fs);
PdfWriter writer = PdfWriter.GetInstance(PDFReport, fs);
//Opening the PDF Doc
PDFReport.Open();
//Load each page from the string into the PDF
page.NextPage();
do
{
if (page.PageLength > 0)
{
Paragraph prg = new Paragraph(page.Page, fontPDF);
PDFReport.Add(prg);
PDFReport.NewPage();
page.NextPage();
}
} while (page.MorePages);
PDFReport.Close();
return (0);
}
I've set the margins to 10 (hardcoded for now) to show what I'm working with. This program should read a string that I send it from my StringBuider class.
It's designed to receive one page of text at a time and to convert it into a PDF document.
Ok, so the problem: when the page is built, the first paragraph doesn't begin at the top margin. If I reduce the margin, it doesn't shift the paragraph up to the new margin. It's causing my PDFs to be much longer as the text that fits easily on a printer page takes two PDF pages. Any help with getting my paragraph to simply begin at the top margin would be really appreciated.
I'm relatively new to programming and this is my first post, so if you need more information, let me know and I'll add more info.
Related
I am using ITextSharp to convert HTML to PDF but i want the PDF to be generated of size 5cm width. I used the following code
var pgSize = new iTextSharp.text.Rectangle(2.05f, 2.05f);
Document doc = new Document(pgSize);
but it is just resizing the pdf and my data disappeared in the pdf or get hide.
How can i align the data in the center in PDF or resize the pdf? Here is my code
public void ConvertHTMLToPDF(string HTMLCode)
{
try
{
System.IO.StringWriter stringWrite = new StringWriter();
System.Web.UI.HtmlTextWriter htmlWrite = new HtmlTextWriter(stringWrite);
StringReader reader = new StringReader(HTMLCode);
var pgSize = new iTextSharp.text.Rectangle(2.05f, 2.05f);
Document doc = new Document(pgSize);
HTMLWorker parser = new HTMLWorker(doc);
PdfWriter.GetInstance(doc, new FileStream(Server.MapPath("~") + "/App_Data/HTMLToPDF.pdf",
FileMode.Create));
doc.Open();
foreach (IElement element in HTMLWorker.ParseToList(
new StringReader(HTMLCode), null))
{
doc.Add(element);
}
doc.Close();
Response.End();
}
catch (Exception ex)
{
}
}
You are creating a PDF that measures 0.0723 cm by 0.0723 cm. That is much too small to add any content. If you want to create a PDF of 5 cm by 5 cm, you need to create your document like this:
var pgSize = new iTextSharp.text.Rectangle(141.732f, 141.732f);
Document doc = new Document(pgSize);
As for the alignment, that should be defined in the HTML, but you are using an old version of iText and you are using the deprecated HTMLWorker.
You should upgrade to iText 7 and pdfHTML as described here: Converting HTML to PDF using iText
Also: the size of the page can be defined in the #page-rule of the CSS. See Huge white space after header in PDF using Flying Saucer
Why would you make it difficult for yourself by using an old iText version, when the new version allows you to do this:
#page {
size: 5cm 5cm;
}
I'm getting only the first two page. I have a generated list of elements in the third page. When there are too many elements in my collection, all pages from there become blank in my pdf output
using (FileStream fs = new FileStream(filePath, FileMode.Create))
{
Document document = new Document(PageSize.A4, 25, 25, 30, 30);
WebClient wc = new WebClient();
string htmlText = wc.DownloadString(textUrl);
PdfWriter pdfWriter = PdfWriter.GetInstance(document, fs);
document.Open();
// register all fonts in current computer
FontFactory.RegisterDirectories();
XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider();
using (var msHtml = new MemoryStream(System.Text.Encoding.Default.GetBytes(htmlText)))
{
//Set factories
var cssAppliers = new CssAppliersImpl(fontProvider);
var htmlContext = new HtmlPipelineContext(cssAppliers);
//HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
htmlContext.SetTagFactory(Tags.GetHtmlTagProcessorFactory());
//FontFactory.Register(arialuniTff);
string gishaTff = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "GISHA.TTF");
FontFactory.Register(gishaTff);
var worker = XMLWorkerHelper.GetInstance();
var cssStream = new FileStream(FolderMapPath("/css/style.css"), FileMode.Open);
worker.ParseXHtml(pdfWriter, document, msHtml, cssStream, new UnicodeFontFactory());
}
// Close the document
document.Close();
// Close the writer instance
pdfWriter.Close();
}
Here is my cshtml code
I only have experience working with iText in Java, but is it possible that the MemoryStream object you are using has a byte limit that gets filled up when the table on page 3 has too many elements for it to store? If that's the case, then the closing tags on that long table may not be written to the MemoryStream, thus that table and everything after doesn't get rendered; i.e. get's truncated by the PDF converter engine.
Can you try using a different Stream object?
Here is how i solved my problem. The problem wasn't with the C# backend code. It's seems like the XMLWorkerHelper at the moment doesn't deal well with loop in view. I had to display list of items in my PDF file. The result was well if the collection contains no so many items, But the page break at the level when the the collection contains more than 50 items because this could not be display in a single page. What i did is that i started to count the number of items and at some number like 40, i just include a break element <li style="list-style:none; list-style-type:none; page-break-before:always">#item</li>. And reset the counter and continue display my items. And it was great and my problem was resolved.
May be this can be helpful for someone.
I've recently used iTextSharp to create a PDF by importing the 20 pages from an existing PDF and then adding a dynamically generated link to the bottom of the last page. It works fine... kind of. Viewing the generated PDF in Acrobat Reader on a windows PC displays everything as expected although when closing the document it always asks "Do you want to save changes?". Viewing the generated PDF on a Surface Pro with PDF Reader displays the document without the first and last pages. Apparently on a mobile device using Polaris Office the first and last pages are also missing.
I'm wondering if when the new PDF is generated it's not getting closed off quite properly and that's why it asks "Do you want to save changes?" when closing it. And maybe that's also why it doesn't display correctly in some PDF reader apps.
Here's the code:
using (var reader = new PdfReader(HostingEnvironment.MapPath("~/app/pdf/OriginalDoc.pdf")))
{
using (
var fileStream =
new FileStream(
HostingEnvironment.MapPath("~/documents/attachments/DocWithLink_" + id + ".pdf"),
FileMode.Create, FileAccess.Write))
{
var document = new Document(reader.GetPageSizeWithRotation(1));
var writer = PdfWriter.GetInstance(document, fileStream);
using (PdfStamper stamper = new PdfStamper(reader, fileStream))
{
var baseFont = BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, BaseFont.CP1252,
BaseFont.NOT_EMBEDDED);
Font linkFont = FontFactory.GetFont("Arial", 12, Font.UNDERLINE, BaseColor.BLUE);
document.Open();
for (var i = 1; i <= reader.NumberOfPages; i++)
{
document.NewPage();
var importedPage = writer.GetImportedPage(reader, i);
// Copy page of original document to new document.
var contentByte = writer.DirectContent;
contentByte.AddTemplate(importedPage, 0, 0);
if (i == reader.NumberOfPages) // It's the last page so add link.
{
PdfContentByte cb = stamper.GetOverContent(i);
//Create a ColumnText object
var ct = new ColumnText(cb);
//Set the rectangle to write to
ct.SetSimpleColumn(100, 30, 500, 90, 0, PdfContentByte.ALIGN_LEFT);
//Add some text and make it blue so that it looks like a hyperlink
var c = new Chunk("Click here!", linkFont);
var congrats = new Paragraph("Congratulations on reading the eBook! ");
congrats.Alignment = PdfContentByte.ALIGN_LEFT;
c.SetAnchor("http://www.domain.com/pdf/response/" + encryptedId);
//Add the chunk to the ColumnText
congrats.Add(c);
ct.AddElement(congrats);
//Tell the system to process the above commands
ct.Go();
}
}
}
}
}
I've looked at these posts with similar issues but none seem to quite provide the answer I need:
iTextSharp-generated PDFs cause save dialog when closing
Using iTextSharp to write data to PDF works great, but Acrobat Reader asks 'Do you want to save changes' when closing file
(Or they refer to memory streams instead of writing to disk etc)
My question is, how do I modify the above so that when closing the generated PDF in Acrobat Reader there's no "Do you want to save changes?" prompt. The answer to that may solve the problems with missing pages on Surface Pro etc but if you know anything else about what might be causing that I'd like to hear about it.
Any suggestions would be very welcome! Thanks!
At first glance (and without much coffee yet) it appears that you're using a PdfReader in three different contexts, as a source to a PdfStamper, as a source for Document and as for a source for importing. So you are essentially importing a document into itself that you're also writing to.
To give you a quick overview, the following code will essentially clone the contents of source.pdf into dest.pdf:
using (var reader = new PdfReader("source.pdf")){
using (var fileStream = new FileStream("dest.pdf", FileMode.Create, FileAccess.Write)){
using (PdfStamper stamper = new PdfStamper(reader, fileStream)){
}
}
}
Since that does all of the cloning for you you don't need to import pages or anything.
Then, if the only thing that you want to do is add some text to the last page, you can just use the above and ask the PdfStamper for a PdfContentByte using GetOverContent() and telling it what page number you're interested. Then you can just use the rest of your ColumnText logic.
using (var reader = new PdfReader("Source.Pdf")) {
using (var fileStream = new FileStream("Dest.Pdf"), FileMode.Create, FileAccess.Write) {
using (PdfStamper stamper = new PdfStamper(reader, fileStream)) {
//Get a PdfContentByte object
var cb = stamper.GetOverContent(reader.NumberOfPages);
//Create a ColumnText object
var ct = new ColumnText(cb);
//Set the rectangle to write to
ct.SetSimpleColumn(100, 30, 500, 90, 0, PdfContentByte.ALIGN_LEFT);
//Add some text and make it blue so that it looks like a hyperlink
var c = new Chunk("Click here!", linkFont);
var congrats = new Paragraph("Congratulations on reading the eBook! ");
congrats.Alignment = PdfContentByte.ALIGN_LEFT;
c.SetAnchor("http://www.domain.com/pdf/response/" + encryptedId);
//Add the chunk to the ColumnText
congrats.Add(c);
ct.AddElement(congrats);
//Tell the system to process the above commands
ct.Go();
}
}
}
I'm very new to using iTextSharp to generate a pdf. I have the following code that places text from my form to the pdf output. I am using a Phrase & ColumnText to position the text from a particular textbox onto my pdf output. I've tied a variable as well as the text property of the textbox as the Phrase string, but it places two sets of the same text on top of each other(screenshot).
string oldFile = Path.GetTempPath() + "invoice.pdf";
string newFile = Path.GetTempPath() + "NewInvoice.pdf";
PdfReader reader = new PdfReader(oldFile);
iTextSharp.text.Rectangle size = reader.GetPageSize(1);
Document doc = new Document(size);
FileStream fs = new FileStream(newFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
PdfWriter writer = PdfWriter.GetInstance(doc, fs);
doc.Open();
PdfContentByte cb = writer.DirectContent;
BaseFont bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, true);
cb.SetColorFill(BaseColor.BLACK);
cb.SetFontAndSize(bf, 12);
cb.BeginText();
cb.ShowTextAligned(PdfContentByte.ALIGN_LEFT, invoiceDate, 480, 603, 0);
cb.EndText();
PdfImportedPage page = writer.GetImportedPage(reader, 1);
cb.AddTemplate(page, 0, 0);
ColumnText ct = new ColumnText(cb);
Phrase phrase = new Phrase(textBox1.Text);
ct.SetSimpleColumn(phrase, 65, 375, 540, 300, 16, Element.ALIGN_LEFT);
ct.Go();
doc.Close();
fs.Close();
writer.Close();
reader.Close();
Process.Start(newFile);
If I assign a string (string whatever = "some text here...";) and place this in the Phrase string(..new Phrase(whatever); it works fine.
Let me start by saying that I'm the original developer of iText.
I hope you'll believe me when I say you should use a PdfReader/PdfStamper combination instead of a Document/PdfWriter combination. This is documented in chapter 6 of my book. You may not see any difference on the outside, but the PDF feel be so much better on the inside.
It's kind of strange that you're adding text at absolute positions. Wouldn't it be better to use a template that has some AcroForm fields on the locations where text is needed? Your code will be so much easier to maintain.
I also see that you're using HELVETICA as font with the parameter for embedding equal to true. Surely you know that the embedded parameter will be ignored for HELVETICA which is one of the Standard Type 1 fonts.
Finally for your question: I don't think your code is adding the phrase twice. I think you've been experimenting and that you're adding a new phrase over a phrase that already exists in the original file "invoice.pdf". If you're 100% that this isn't the case, then you should share your PDF so that I (or somebody else at iText) can inspect it.
I am trying to do something relatively simple with iTextSharp, but I always find it very confusing and can't figure out this without asking for some help.
I have a situation where a third party product I use generates a PDF, but doesn't have the option of setting initial view settings (zoom, fit to width, etc).
I have found some code that will allows me to do this in iTextSharp :-
Developer Barn
The bit I cannot work out is how to apply this to a file that already exists - this seems to be fine for any new files, or something I am creating in iTextSharp, but not an existing PDF. Is there a way of doing this, and how can it be done?
Many thanks in advance,
Adam
PS - Already found the answer to this.. StackOverflow won't let me close my own question though? Seems a bit daft, but anyway do it like this -
PdfReader reader = new PdfReader(new FileStream(fileName, FileMode.Open, FileAccess.Read));
Rectangle size = reader.GetPageSizeWithRotation(1);
using (Document document = new Document(size))
{
using (PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(Path.Combine(Path.GetDirectoryName(fileName), "Zoom" + Path.GetFileName(fileName)), FileMode.Create, FileAccess.ReadWrite)))
{
//open our document
document.Open();
PdfContentByte cb = writer.DirectContent;
//this creates a new destination to send the action to when the document is opened.
PdfDestination pdfDest = new PdfDestination(PdfDestination.FITH, reader.GetPageSize(1).Top);
//create a new action to send the document to our new destination.
PdfAction action = PdfAction.GotoLocalPage(1, pdfDest, writer);
for (int pageNumber = 1; pageNumber <= reader.NumberOfPages; pageNumber++)
{
//need to change page size for landscape / portrait
document.SetPageSize(reader.GetPageSizeWithRotation(pageNumber));
document.NewPage();
PdfImportedPage page = writer.GetImportedPage(reader, pageNumber);
cb.AddTemplate(page, 0, 0);
}
//set the page mode
int PageMode = 0;
PageMode += PdfWriter.PageLayoutOneColumn;
//set the open action for our writer object
writer.SetOpenAction(action);
writer.ViewerPreferences = PageMode;
writer.SetFullCompression();
//finally, close our document
document.Close();
}
}
I don't think there is an edit functionnality per se, neither in iTextSharp nor in iText. I think the way to go is to open the existing document, create a new writer, copy the old document into the new writer while adding the enrichments you'd like to see and overwrite the original doc afterwards as decribed here.