I'm using iTextSharp 5.0.5 to create dynamic PDFs (asp.net c#), and I'm having problems with an extra space being inserted when creating a new page. The first page looks fine but on any additional pages the extra space appears at the top.
I've made a mini example that inserts a new page with a logo and a title for each article in a list. If I only insert the logo or only the title it works fine, but if I try to insert both there's an extra space coming from somewhere. Anyone got any ideas of what I'm doing wrong?
public static void CreatePDF(List<Item> Articles)
{
Document document = new Document(PageSize.A4, 35, 35, 35, 35);
MemoryStream memoryStream = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(document, memoryStream);
document.Open();
for (int i = 0; i < Articles.Count; i++)
{
if (i > 0)
{
document.NewPage();
}
Image logo = Image.GetInstance(#"C:\logo.gif");
document.Add(logo);
Paragraph title = new Paragraph("test title", new Font(Font.FontFamily.HELVETICA, 20, Font.NORMAL, CMYKColor.BLACK));
document.Add(title);
}
document.Close();
SendPDFResponse(memoryStream, "myfile.pdf");
}
Thanks,
Annelie
There's no extra space on the pages that follow page 1. The problem is that there's less space on page 1.
No, this is not a joke. The problem is caused by the "leading" (that is: the space between two lines). The initial value for the leading is 0. When you add content to a document, this value changes to a value different from 0.
What is the leading you're using throughout the document? You should set this as the initial leading with the method setInitialLeading() in PdfWriter.
That sounds like a bug. I suspect some relatively new aspect of layout isn't being reset properly between pages.
Would you mind cross-posting this to the itext-questions mailing list?
Related
I have this code which I merged and modified for my needs. But I still can't make it work as I need. The first part that I made, it generates PDF with an option from aspx page chosen. Second, I need to have the background over the page, so I added next code, but now it generates just the second code and not the PDF. And im not able to merge those codes together.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
public partial class CreatePDFFromScratch : System.Web.UI.Page
{
protected void btnCreatePDF_Click(object sender, EventArgs e)
{
// Create a Document object
var document = new Document(iTextSharp.text.PageSize.LETTER.Rotate(), 0f, 0f, 0f, 0f);
// Create a new PdfWrite object, writing the output to a MemoryStream
var output = new MemoryStream();
var writer = PdfWriter.GetInstance(document, output);
// Open the Document for writing
document.Open();
// First, create our fonts..
var titleFont = FontFactory.GetFont("Arial", 18, Font.BOLD);
var subTitleFont = FontFactory.GetFont("Arial", 14, Font.BOLD);
var boldTableFont = FontFactory.GetFont("Arial", 12, Font.BOLD);
var endingMessageFont = FontFactory.GetFont("Arial", 10, Font.ITALIC);
var bodyFont = FontFactory.GetFont("Arial", 12, Font.NORMAL);
// Add the "Northwind Traders Receipt" title
document.Add(new Paragraph("Northwind Traders Receipt", titleFont));
// Now add the "Thank you for shopping at Northwind Traders. Your order details are below." message
document.Add(new Paragraph("Thank you for shopping at Northwind Traders. Your order details are below.", bodyFont));
document.Add(Chunk.NEWLINE);
// Add the "Order Information" subtitle
document.Add(new Paragraph("Order Information", subTitleFont));
// Create the Order Information table
var orderInfoTable = new PdfPTable(2);
orderInfoTable.HorizontalAlignment = 0;
orderInfoTable.SpacingBefore = 10;
orderInfoTable.SpacingAfter = 10;
orderInfoTable.DefaultCell.Border = 0;
orderInfoTable.SetWidths(new int[] { 1, 4 });
orderInfoTable.AddCell(new Phrase("Order:", boldTableFont));
orderInfoTable.AddCell(txtOrderID.Text);
orderInfoTable.AddCell(new Phrase("Price:", boldTableFont));
orderInfoTable.AddCell(Convert.ToDecimal(txtTotalPrice.Text).ToString("c"));
document.Add(orderInfoTable);
// Add the "Items In Your Order" subtitle
document.Add(new Paragraph("Items In Your Order", subTitleFont));
// Create the Order Details table
var orderDetailsTable = new PdfPTable(3);
orderDetailsTable.HorizontalAlignment = 0;
orderDetailsTable.SpacingBefore = 10;
orderDetailsTable.SpacingAfter = 35;
orderDetailsTable.DefaultCell.Border = 0;
orderDetailsTable.AddCell(new Phrase("Item #:", boldTableFont));
orderDetailsTable.AddCell(new Phrase("Item Name:", boldTableFont));
orderDetailsTable.AddCell(new Phrase("Qty:", boldTableFont));
foreach (System.Web.UI.WebControls.ListItem item in cblItemsPurchased.Items)
if (item.Selected)
{
// Each CheckBoxList item has a value of ITEMNAME|ITEM#|QTY, so we split on | and pull these values out...
var pieces = item.Value.Split("|".ToCharArray());
orderDetailsTable.AddCell(pieces[1]);
orderDetailsTable.AddCell(pieces[0]);
orderDetailsTable.AddCell(pieces[2]);
}
document.Add(orderDetailsTable);
// Add ending message
var endingMessage = new Paragraph("Thank you for your business! If you have any questions about your order, please contact us at 800-555-NORTH.", endingMessageFont);
endingMessage.SetAlignment("Center");
document.Add(endingMessage);
document.Close();
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", string.Format("inline;filename=Receipt-{0}.pdf", txtOrderID.Text));
///create background
Response.BinaryWrite(output.ToArray());
Response.Cache.SetCacheability(HttpCacheability.NoCache);
string imageFilePath = Server.MapPath(".") + "/images/1.jpg";
iTextSharp.text.Image jpg = iTextSharp.text.Image.GetInstance(imageFilePath);
Document pdfDoc = new Document(iTextSharp.text.PageSize.LETTER.Rotate(), 0, 0, 0, 0);
jpg.ScaleToFit(790, 777);
jpg.Alignment = iTextSharp.text.Image.UNDERLYING;
pdfDoc.Open();
pdfDoc.NewPage();
pdfDoc.Add(jpg);
pdfDoc.Close();
Response.Write(pdfDoc);
Response.End();
}
}
Thanks
I almost missed this question because it wasn't tagged as an itext question.
First let me copy/paste/adapt #mkl's comment:
The first part of your code in which you create a document document makes sense.
The second part in which you create a document pdfDoc does not.
First of all, at the end of the first part you write the pdf to
the response. That PDF is complete. It's finished. It's done.
It's ready to send to the browser.
Why do you think anything additional written to the
response thereafter might have a chance of combining with the original
written data to a properly generated PDF?
Also: the second part of your code is
written as if you want to create a new PDF from scratch; but didn't you
want to manipulate the PDF created in the first part?
All of this is true, but it doesn't solve your problem. It only reveals your deep lack of understanding in PDF.
There are different ways to achieve what you want. I see that you want to use an image as a background of all the pages of a newly created PDF. In that case, you should create a page event, and add that image underneath all the existing content in the OnEndPage() method. This is explained in the answer to How can I add an image to all pages of my PDF?
Create a PDF as is done in the first part of your code, but introduce a page event:
// step 1
Document document = new Document();
// step 2
PdfWriter writer = PdfWriter.GetInstance(document, stream);
MyEvent event = new MyEvent();
writer.PageEvent = event;
// step 3
document.Open();
// step 4
// Add whatever content you want to add
// step 5
document.Close();
What is the MyEvent class, you might ask? Well, that's a class you create yourself like this:
protected class MyEvent : PdfPageEventHelper {
Image image;
public override void OnOpenDocument(PdfWriter writer, Document document) {
image = Image.GetInstance(Server.MapPath("~/images/background.png"));
image.SetAbsolutePosition(0, 0);
}
public override void OnEndPage(PdfWriter writer, Document document) {
writer.DirectContent.AddImage(image);
}
}
Suppose that your requirement isn't as easy as adding an image in the background, then you could use the bytes created as output to create a PdfReader instance. You could then use the PdfReader to create a PdfStamper and you can use the PdfStamper to watermark the original document. If the simple solution doesn't meet your needs, create a new question that involves PdfReader/PdfStamper and don't forget to tag that question as an iText question. (And also: please read the documentation. A lot of time was spent on the iText web site. That time was wasted if you don't consult it.)
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.
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 am using iTextSharp for PDF generating in Unity3d.
EDIT
Here is the code, but I am getting an empty PDF document:
void createPDF()
{
Document doc = new Document(iTextSharp.text.PageSize.A1, 5, 5, 5, 5);
PdfWriter wri = PdfWriter.GetInstance(doc, new FileStream("TestPDF.pdf", FileMode.Create));
doc.Open();
string fontPath = "C:\\windows\\Fonts\\arialuni.ttf";
BaseFont basefont = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
iTextSharp.text.Font tahomaFont = new iTextSharp.text.Font(basefont, 10, iTextSharp.text.Font.NORMAL, BaseColor.RED);
PdfContentByte cb = wri.DirectContent;
ColumnText ct = new ColumnText(cb);
Phrase myText = new Phrase(GameObject.Find("TextPlay").GetComponent<TextMesh>().text);
ct.SetSimpleColumn(myText, 34, 750, 580, 317, 15, Element.ALIGN_LEFT);
ct.Go();
doc.Close();
}
The error message tells you that the font ArialJezici.ttf can't be used with encoding Identity_H, hence you will have to replace that font with another one, for instance with ArialUni.ttf.
Actually, this should work:
BaseFont bf = iTextSharp.text.pdf.BaseFont.CreateFont("C:\\WINDOWS\\Fonts\\ARIALUNI.TTF", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
Note that you need to provide the correct path. I don't think you're doing that in your example.
If the above snippet doesn't work, see itextsharp ARIALUNI.TTF copy on hosting server for an alternative example on how to do this.
Note that Arabic ligatures only work in the context of PdfPCell and ColumnText objects, they do not work in a Paragraph added to the Document because you can not set the run direction of a Paragraph. You can only set the run direction of a cell or a column.
If you do not set your run direction, the Arabic text will be written from left to right and no ligatures will be made, resulting in something this is not correct Arabic.
Contrary to the rules on StackOverflow, the original question was changed, resulting in my answer no longer being the answer to the new version of the question. This is an update with the anser to the current question:
With the BaseFont created in the first part of my answer, create a Font:
Font font = new Font(bf, 20);
Now create a ColumnText object and provide coordinates that fit your page:
ColumnText column = new ColumnText(writer.DirectContent);
column.SetSimpleColumn(36, 730, 569, 36);
If these coordinates do not fit your page, your content will be added to the file, but you won't see anything because the content is outside the visible area of the page.
For Arabic text, it is important that you set the run direction (I don't see you doing that anywhere):
column.RunDirection = PdfWriter.RUN_DIRECTION_RTL;
Now add the content:
column.AddElement(new Paragraph(GameObject.Find("TextPlay").GetComponent<TextMesh>().text));
column.Go();
This works for me, see the Java example or corresponding C# example, resulting in this file: ligatures_2.pdf
That file shows the Arabic text "لورانس العرب" three times. The first time, the characters are not in the right order. The second time, the characters are in the right order, but no ligatures are being made. The third time, it is shown correctly.
I want to put a check mark using zapfdingbatslist on my pdf document in iTextSharp in a specific location.
What I could do so far is I could show the check mark but it's all on the side of the document and not on a specific X, Y coordinate that I want it to be. I have a code below that would hopefully give you the idea of what I am talking about.
String outputFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Test.pdf");
System.IO.FileStream fs;
Document doc = new Document(PageSize.A4, 20, 20, 10, 10);
PdfContentByte cb;
PdfWriter writer;
fs = new System.IO.FileStream(outputFile, System.IO.FileMode.Create);
writer = PdfWriter.GetInstance(doc, fs);
doc.SetPageSize(iTextSharp.text.PageSize.A4.Rotate());
writer.AddViewerPreference(PdfName.PICKTRAYBYPDFSIZE, PdfBoolean.PDFTRUE);
doc.Open();
cb = writer.DirectContent;
List myList = new ZapfDingbatsList(52); // Check mark symbol from Dingbatslist
// I have some more code here but it is not needed for the problem
// and thererfore not shown
// I could shohw the dingbatslist check mark here
myList.Add(" ");
doc.Add(myList); // However I want to show it in a specific X, Y position
doc.Close();
writer.Close();
fs.Close();
Any idea?
Incidentally, I'm the author of most of the iText documentation (as well as the original developer of iText, including the Document, PdfWriter, ZapfdingbatsList,... classes), and I'd appreciate it if you took some time to read the iText documentation.
Let's start with chapter 2 and take a look at some C# examples that introduce the Font class.
For instance:
Font font = new Font(Font.FontFamily.ZAPFDINGBATS, 12);
Once you have a Font object, you can create a Phrase (also explained in chapter 2):
Phrase phrase = new Phrase(zapfstring, font);
Where zapfstring is a string containing any Zapfdingbats character you want.
To add this Phrase at an absolute position, you need to read chapter 3. Take a look at the examples for inspiration, for instance FoobarFilmfestival.cs:
PdfContentByte canvas = writer.DirectContent;
ColumnText.ShowTextAligned(canvas, Element.ALIGN_CENTER, phrase, 200, 500, 0);
Where 200 and 500 are an X and Y coordinate and 0 is an angle expressed in degrees. Instead of ALIGN_CENTER, you can also choose ALIGN_RIGHT or ALIGN_LEFT.
In your code sample you were adding a Zapfdingbats glyph to a document using a list. Please take a moment to put yourself in my place. Doesn't that feel as if you're the inventor of the sock attending a Red Hot Chili Peppers' concert?