I'm having an issue with flattening fields that were generated in a table cell. I've created a sample project to illustrate the issue.
private static void dummyFunction2()
{
// Create a PDF with a TextBox in a table cell
//Get the font ready
BaseFont bfHelvetica = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1250, false);
var helvetica12 = new Font(bfHelvetica, 12, Font.NORMAL, BaseColor.BLACK);
//Create the document and filestream
var doc = new Document(PageSize.LETTER, 18f, 18f, 18f, 18f);
var fs = new FileStream("TextBoxInTableCell.pdf", FileMode.Create);
PdfWriter writer = PdfWriter.GetInstance(doc, fs);
//Create the table
doc.Open();
var myTable = new PdfPTable(1);
myTable.TotalWidth = 568f;
myTable.LockedWidth = true;
myTable.HorizontalAlignment = 0;
//Create the textfield that will sit on a cell in the table
var tf = new TextField(writer, new Rectangle(67, 585, 140, 800), "cellTextBox");
tf.Text = "test";
//Create the table cell
var tbCell = new PdfPCell(new Phrase(" ", helvetica12));
//Use fieldpositioningevents to make the field appear on top of the cell
var events =
new FieldPositioningEvents(writer, tf.GetTextField());
tbCell.CellEvent = events;
//Add the cell to the table
myTable.AddCell(tbCell);
PdfContentByte cb = writer.DirectContent;
//Write out the table to the middle of the document
myTable.WriteSelectedRows(0, -1, 0, -1, 0, 400, cb);
doc.Close();
fs.Close();
//Open back up the document so that we can set GenerateAppearances to false.
//This solution proposed and accepted at https://stackoverflow.com/questions/25169342/itextsharp-fields-generated-in-a-table-not-shown-in-adobe-reader
var reader2 = new PdfReader("TextBoxInTableCell.pdf");
var stamper2 = new PdfStamper(reader2, new FileStream("tempdoc.pdf", FileMode.Create));
stamper2.AcroFields.GenerateAppearances = false;
stamper2.Close();
reader2.Close();
Process.Start("tempdoc.pdf");
//Open the pdf back up
var reader = new PdfReader("tempdoc.pdf");
var stamper = new PdfStamper(reader, new FileStream("tempdoc.pdf" + "1.pdf", FileMode.Create));
//Flatten the form
stamper.FormFlattening = true;
//Close everything
stamper.Close();
reader.Close();
Process.Start("tempdoc.pdf" + "1.pdf");
}
This unflattened pdf that is generated looks like . As you can see, the field is where it should be. The flattened pdf, however, looks like . The field's text has been shifted a noticeable amount.
I've posted the flattened pdf so that someone can check out the pdf language if needed.
I know this is sort of a niche issue but hopefully someone can help me out.
EDIT1: In response to Bruno's comment, I'm using iTextsharp 5.5.2 downloaded from Nuget and the unflattened pdf can be found here.
EDIT2: Updated SO link to point to the correct question. For reference here are my two previous questions that relate to this problem: First, Second
Java version of iText does not contain this problem. It's a Java -> C# porting issue. We'll take care of that.
Related
I am creating a PDF Document consisting 6 images (1 Image on 1 Page) using iTextSharp.
I need to add a HTML Page as a last page after the 6th Image.
I have tried the below, but the HTML does not get added on a new page, instead gets attached immediately below the 5th Image.
Please advice how to make the html add to the last page.
Code for reference:
string ImagePath = HttpContext.Current.Server.MapPath("~/Images/");
string[] fileNames = System.IO.Directory.GetFiles(ImagePath);
string outputFileNames = "Test.pdf";
string outputFilePath = System.Web.Hosting.HostingEnvironment.MapPath("~/Pdf/" + outputFileNames);
Document doc = new Document(PageSize.A4, 20, 20, 20, 20);
System.IO.Stream st = new FileStream(outputFilePath, FileMode.Create, FileAccess.Write);
PdfWriter writer = PdfWriter.GetInstance(doc, st);
doc.Open();
writer.PageEvent = new Footer();
for (int i = 0; i < fileNames.Length; i++)
{
string fname = fileNames[i];
if (System.IO.File.Exists(fname) && Path.GetExtension(fname) == ".png")
{
iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(fname);
img.Border = iTextSharp.text.Rectangle.BOX;
img.BorderColor = iTextSharp.text.BaseColor.BLACK;
doc.Add(img);
}
}
byte[] pdf; // result will be here
var cssText = File.ReadAllText(MapPath("~/Style1.css"));
var html = File.ReadAllText(MapPath("~/HtmlPage1.html"));
using ( var memoryStream = new MemoryStream())
{
using (var cssMemoryStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(cssText)))
{
using (var htmlMemoryStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(html)))
{
XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, htmlMemoryStream, cssMemoryStream);
}
}
pdf = memoryStream.ToArray();
//document.Add(new Paragraph(Encoding.UTF8.GetString(pdf)));
}
doc.NewPage();
doc.Add(new Paragraph(Encoding.UTF8.GetString(pdf)));
doc.Close();
writer.Close();
I need to add a HTML Page as a last page after the 6th Image.
Any help is appreciated
In contrast to what you assume according to your code comments, pdf is not where the result will be. It remains empty:
byte[] pdf; // result will be here
...
using ( var memoryStream = new MemoryStream())
{
... code not accessing memoryStream ...
pdf = memoryStream.ToArray();
//document.Add(new Paragraph(Encoding.UTF8.GetString(pdf)));
}
doc.NewPage();
doc.Add(new Paragraph(Encoding.UTF8.GetString(pdf)));
Thus, you add the new page before adding an empty paragraph, after the converted html already has been added to the document.
Actually it is added during
XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, htmlMemoryStream, cssMemoryStream);
So you have to add the new page before that. Thus, the following replacing everything from your byte[] pdf; on should do the job:
var cssText = File.ReadAllText(MapPath("~/Style1.css"));
var html = File.ReadAllText(MapPath("~/HtmlPage1.html"));
using (var cssMemoryStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(cssText)))
{
using (var htmlMemoryStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(html)))
{
doc.NewPage();
XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, htmlMemoryStream, cssMemoryStream);
}
}
doc.Close();
As an aside, don't close the writer! It implicitly is closed when the doc is closed. Closing it again does nothing at best or damage otherwise.
In a comment you claimed
but this also does not resolve the issue... the pdf content still get added after the image and then continued on new page.
So I tested the proposed change. Obviously I don't have your environment and also not your image, html, and css files. Thus, I used own ones, a small screen shot and "<html><body><h1>Test</h1><p>This is a test piece of html</p></body></html>".
With your code I get:
With the code changed as described above I get
My impression here is that the proposed code change does resolve the issue. The html content is added on a new page.
Thus apparently your either incorrectly applied the proposed change, or you executed old code, or you inspected some old result.
I'm creating an application in c# for generation of some pdf files with bar code in it.
I'm using the memory stream and placing data to the table (one column) which I'll write to the pdf file at the end.
Everything is working fine till I need to add bar code. For that I use direct content.
pdfWriter = PdfWriter.GetInstance(pdfToCreate, outputStream);
PdfContentByte cb = new PdfContentByte(pdfWriter);
iTextSharp.text.Image bc128 = code128.CreateImageWithBarcode(cb, null, null);
After I create bar code I add it to the table using:
tableout.AddCell(image128);
And then I have a problem. Rows from the table that I've created before are shown, but I don't see a text. If I comment line with bar code addition everything is OK.
I've found one comment on forum:
Yep. Foreground text color is defined by the Font for the high-level
text layout code. When you start using a PdfContentByte directly, the
font and color become separated, but not until then.
How can I solve this?
I know that I can use system drawning method but image with bar code is not so clear.
PdfContentByte is for direct rendering to absolute positions in the pdf. But what you need is an IElement you can add to the "document stack".
Try this (using full namespaces just to clearly identify the classes):
Barcode128 barcode = new Barcode128();
System.Drawing.Image img = barcode.CreateDrawingImage(System.Drawing.Color.Black, System.Drawing.Color.White);
iTextSharp.text.Image itextImg = iTextSharp.text.Image.GetInstance(img, System.Drawing.Imaging.ImageFormat.Bmp);
table.AddCell(new PdfPCell(itextImg));
I know that I can use system drawning method but image with bar code is not so clear.
Here is a code that I use. I'm trying to get documents whit different sizes depending on the number of lines in the document. So I'm using memory stream (not shown here). My idea is to write data to the table in memory and count lines. After that I will create new pdf document and add table to that document.
If I comment a line:
table.AddCell(image128);
both documents are the same. But if I leave that line in code final document shows all rows but text in rows is not visible. If I open second docu,ent in firefox I can even see a bar codes.
Any suggestion will be great. Or is there a different way to get documents with different sizes depending on amount of content.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.IO;
using System.Drawing;
namespace testtables1
{
class Program
{
static void Main(string[] args)
{
iTextSharp.text.Rectangle pageSize = new iTextSharp.text.Rectangle(300, 720);
Document pdfToCreate = new Document(pageSize, 0, 0, 0, 0);
PdfWriter writer = PdfWriter.GetInstance(pdfToCreate, new FileStream(#"D:\\testfile.pdf", FileMode.Create));
pdfToCreate.Open();
PdfPTable table = new PdfPTable(1);
PdfPTable tableout = new PdfPTable(1);
WriteLineToPdf("This is first row. Below is image generated using SystemDrawing.", table, out tableout);
table = tableout;
// Create bar code
Barcode128 code128 = new Barcode128();
code128.CodeType = Barcode.CODE128;
code128.ChecksumText = true;
code128.GenerateChecksum = true;
code128.Code = "00100370006756555316";
// Create a new PdfWrite object, writing the output to a MemoryStream
var outputStream = new MemoryStream();
var pdfWriter = PdfWriter.GetInstance(pdfToCreate, outputStream);
PdfContentByte cb = new PdfContentByte(writer);
// Image generated using System.Drawing and rendering
System.Drawing.Bitmap bm = new System.Drawing.Bitmap(code128.CreateDrawingImage(System.Drawing.Color.Black, System.Drawing.Color.White));
iTextSharp.text.Image bmCoverted = iTextSharp.text.Image.GetInstance(bm, System.Drawing.Imaging.ImageFormat.Bmp);
table.AddCell(bmCoverted);
pdfToCreate.Open();
// Image generated using iTextSharp.text.Image
WriteLineToPdf("This is third row. Below is image generated using code128.CreateImageWithBarcode.", table, out tableout);
table = tableout;
iTextSharp.text.Image image128 = code128.CreateImageWithBarcode(cb, null, null);
table.AddCell(image128);
table = tableout;
WriteLineToPdf("This is fifth row.", table, out tableout);
pdfToCreate.Add(tableout);
// Create new document with height that depends on number of lines in document.
iTextSharp.text.Rectangle psFinal = new iTextSharp.text.Rectangle(200, 300);
Document pdfFinal = new Document(psFinal, 0, 0, 0, 0);
PdfWriter writer1 = PdfWriter.GetInstance(pdfFinal, new FileStream(#"D:\\finalfile.pdf", FileMode.Create));
pdfFinal.Open();
pdfFinal.Add(tableout);
cb = null;
pdfToCreate.Close();
pdfFinal.Close();
}
// Write a single line to the PDF.
private static void WriteLineToPdf(string tLine, PdfPTable ticTable0In, out PdfPTable ticTableIN)
{
// Define fonts.
BaseFont bfTimes = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1252, false); // Base font.
iTextSharp.text.Font timesN = new iTextSharp.text.Font(bfTimes, 12, iTextSharp.text.Font.NORMAL, BaseColor.BLACK);
Paragraph par = new Paragraph(tLine, timesN);
par.Alignment = Element.ALIGN_CENTER;
PdfPCell cell;
cell = new PdfPCell();
//cell.FixedHeight = 12f;
//cell.Border = Rectangle.NO_BORDER;
cell.AddElement(par);
ticTable0In.AddCell(cell);
ticTableIN = ticTable0In;
par = null;
}
}
}
My other ideai is to use data from memory stream. I'm able to create result.pdf document with size that I want but after I write Data from memory size changes.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
namespace TableWithBC2
{
class Program
{
static void Main(string[] args)
{
using (MemoryStream myMemoryStream = new MemoryStream())
{
PdfPTable tableIn;
Document pdfDocument = new Document();
PdfWriter writer = PdfWriter.GetInstance(pdfDocument, myMemoryStream);
PdfPTable tableOut = new PdfPTable(new float[] { 200 });
tableIn = new PdfPTable(new float[] { 200 });
pdfDocument.Open();
for (int i = 0; i < 5; i++)
{
WriteLineToPdf("This is row no. " + i.ToString(), tableIn, out tableOut);
tableIn = tableOut;
}
// Create bar code
PdfContentByte cb = writer.DirectContent;
Barcode128 code128 = new Barcode128();
code128.CodeType = Barcode.CODE128;
code128.ChecksumText = true;
code128.GenerateChecksum = true;
code128.Code = "00100370006756555316";
Image barCodeImage = code128.CreateImageWithBarcode(cb, null, null);
PdfPCell cell1 = new PdfPCell(barCodeImage);
tableOut.AddCell(cell1);
tableIn = tableOut;
WriteLineToPdf("This is a last row.", tableIn, out tableOut);
pdfDocument.Add(tableOut);
pdfDocument.Close();
// Create final PDF document.
Document pdfDocument1 = new Document(new Rectangle(200, 250));
PdfWriter writer1 = PdfWriter.GetInstance(pdfDocument1, new FileStream(#"D:\\result.pdf", FileMode.Create));
pdfDocument1.Open();
pdfDocument1.Add(new Chunk());
pdfDocument1.Close();
byte[] content = myMemoryStream.ToArray();
// Write out PDF from memory stream.
using (FileStream fs = File.OpenWrite(#"D:\\nikola bd - final\\out\\dummy22.pdf"))
{
fs.Write(content, 0, (int)content.Length);
}
}
}
// Write a single line to the PDF.
private static void WriteLineToPdf(string tLine, PdfPTable tTableIn, out PdfPTable tTableOut)
{
BaseFont bfTimes = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1252, false);
iTextSharp.text.Font timesN = new iTextSharp.text.Font(bfTimes, 12, iTextSharp.text.Font.NORMAL, BaseColor.RED);
Paragraph par = new Paragraph(tLine, timesN);
par.Alignment = Element.ALIGN_CENTER;
PdfPCell cell = new PdfPCell();
cell.AddElement(par);
tTableIn.AddCell(cell);
tTableOut = tTableIn;
}
}
}
I'm still a beginner in C# and I want to know is there an option of writing slavic letters č,ć,š,ž in PDF using iTextSharp. I was reading other posts about it but I can't apply their solution to my problem, maybe it's a bit to complicate to me as a beginner. This is my code:
SaveFileDialog pdfFile = new SaveFileDialog();
pdfFile.Filter = "PDF|*.pdf";
pdfFile.Title = "Spremi PDF";
pdfFile.FileName = "Ispit";
if (pdfFile.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
Document document = new Document(iTextSharp.text.PageSize.LETTER, 25, 25, 35, 35);
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(pdfFile.FileName, FileMode.Create));
document.Open();
foreach (List<string> question in questions)
{
document.NewPage();
foreach (string field in question)
{
document.Add(new Paragraph(field));
}
}
document.Close();
}
This code is maybe to simple and maybe there's a lots of better ways to do this but this is one of my first codes in C#.
I have solved my problem. This is the code that helped me:
BaseFont bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1250, false);
Font titleFont = new Font(bf,20);
Font infoFont = new Font(bf,16);
Thank you all
here is What i want i want to add page numbers to every pdf page that i generated on the fly.
i used on end page method but it did not worked out even when i added the doc bottom margin.
I decided to add the page numbers after the pdf is generated from the file path.
here is my code for generating pdf:
Document doc = new Document(iTextSharp.text.PageSize.LETTER, 10, 10, 42, 35);
PdfWriter wri = PdfWriter.GetInstance(doc, new FileStream("t5.pdf", FileMode.Create));
doc.Open();//Open Document to write
iTextSharp.text.Font font8 = FontFactory.GetFont("ARIAL", 7);
Paragraph paragraph = new Paragraph("Some content");
doc.Add(paragraph);
doc.Add(paragraph);// add paragraph to the document
doc.Close();
FileStream stream = File.OpenRead("t5.pdf");
byte[] fileBytes = new byte[stream.Length];
stream.Read(fileBytes, 0, fileBytes.Length);
stream.Close();
AddPageNumbers(fileBytes);
using (Stream file = File.OpenWrite("t5.pdf"))
{
file.Write(fileBytes, 0, fileBytes.Length);
}
}
and her is my add pagenumbers method:
MemoryStream ms = new MemoryStream();
PdfReader reader = new PdfReader(pdf);
int n = reader.NumberOfPages;
iTextSharp.text.Rectangle psize = reader.GetPageSize(1);
Document document = new Document(psize, 50, 50, 50, 50);
PdfWriter writer = PdfWriter.GetInstance(document, ms);
document.Open();
PdfContentByte cb = writer.DirectContent;
int p = 0;
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_CENTER, +p + "/" + n, 100, 450, 0);
cb.EndText();
}
document.Close();
return ms.ToArray();
how ever it does not add the page numbers to the pdf document so what is the alternatives here? what can i do.
When posting a question here, please only post the smallest amount of code possible. Your "create a sample PDF with multiple pages" is 116 lines long. Inside of it you've got complicated PdfPTable and DataTable logic that is 100% unrelated to the problem. Instead, the following 13 lines is enough to make a multiple page PDF:
//Create a sample multiple page PDF and place it on the desktop
var outputFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "t5.pdf");
using (var fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (var doc = new Document()) {
using (var writer = PdfWriter.GetInstance(doc, fs)) {
doc.Open();
for (var i = 0; i < 1000; i++) {
doc.Add(new Paragraph(String.Format("This is paragraph #{0}", i)));
}
doc.Close();
}
}
}
Second, get rid of try/catch. Those are great for production (sometimes) but at the development level that's why we have IDEs and compilers, they'll tell us specifically what's wrong.
Now on to the bigger problem, you need to keep these two processes separate from each other. Every single brace and object from part part #1 must be closed, done and accounted for. Part #2 then needs to be fed a completely valid PDF but neither of the two parts should be "aware" of each other or depend on each other.
Since you just borrowed some code that wasn't intended for what you're trying to do I'm going to also ignore that and use some code that I know specifically will work. Also, since you're open to using a MemoryStream in the first place I'm just going to avoid writing to disk until I need to. Below is a full working sample that creates a multiple page and then adds page numbers in a second pass.
//Will hold our PDF as a byte array
Byte[] bytes;
//Create a sample multiple page PDF, nothing special here
using (var ms = new MemoryStream()) {
using (var doc = new Document()) {
using (var writer = PdfWriter.GetInstance(doc, ms)) {
doc.Open();
for (var i = 0; i < 1000; i++) {
doc.Add(new Paragraph(String.Format("This is paragraph #{0}", i)));
}
doc.Close();
}
}
//Store our bytes before
bytes = ms.ToArray();
}
//Read our sample PDF and apply page numbers
using (var reader = new PdfReader(bytes)) {
using (var ms = new MemoryStream()) {
using (var stamper = new PdfStamper(reader, ms)) {
int PageCount = reader.NumberOfPages;
for (int i = 1; i <= PageCount; i++) {
ColumnText.ShowTextAligned(stamper.GetOverContent(i), Element.ALIGN_CENTER, new Phrase(String.Format("Page {0} of {1}", i, PageCount)), 100, 10 , 0);
}
}
bytes = ms.ToArray();
}
}
var outputFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "t5.pdf");
System.IO.File.WriteAllBytes(outputFile, bytes);
Using .NET, I want to programmatically create a PDF which simply consists of a background image with two labels over it with different fonts and positioning. I have read about existing PDF libraries, but don't know (if applicable) which one is the easiest for such a simple task.
Anyone care to guide me?
P.D.: I do not want to create the PDF with a generated image that already overlays the text over the background image.
Edit: This is the final working code:
public string Create()
{
if (!Directory.Exists(ApplicationImagePath))
{
Directory.CreateDirectory(ApplicationImagePath);
}
// Smart card
var doc = new Document(PageSize.GetRectangle("153 242.65"), 0, 0, 0, 0);
using (var stream = File.Create(filepath))
{
var writer = PdfWriter.GetInstance(doc, stream);
doc.Open();
var image = Image.GetInstance(CarnetData.Frame, ImageFormat.Png);
image.Alignment = Element.ALIGN_CENTER;
image.ScaleToFit(153, 242.65f);
doc.Add(image);
BaseFont font = BaseFont.CreateFont(GetFontPath(CarnetConfiguration.FontType), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
font.PostscriptFontName = CarnetConfiguration.FontType.ToString();
float verticalPosition = writer.GetVerticalPosition(false);
var pName = new Paragraph(CarnetData.Name, new Font(font, FontData.EmployeeFont.SizeInPoints))
{
SpacingBefore = verticalPosition - 51f,
MultipliedLeading = 1.1f,
Alignment = Element.ALIGN_CENTER
};
doc.Add(pName);
var pDepartment = new Paragraph(CarnetData.Department, new Font(font, FontData.DepartmentFont.SizeInPoints))
{
SpacingBefore = 1.5f,
MultipliedLeading = 1.2f,
Alignment = Element.ALIGN_CENTER
};
doc.Add(pDepartment);
writer.ViewerPreferences = PdfWriter.PageModeUseNone + PdfWriter.CenterWindow + PdfWriter.PageLayoutSinglePage;
doc.Close();
}
return filepath;
}
Thanks for the help. :)
iTextSharp is a great library you could use, very simple and intuitive:
var doc = new Document();
using (var stream = File.Create("output.pdf"))
{
var writer = PdfWriter.GetInstance(doc, stream);
doc.Open();
doc.Add(Image.GetInstance(#"c:\foo\test.png"));
var cb = writer.DirectContent;
cb.BeginText();
cb.SetTextMatrix(100, 220);
var font = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1252, false);
cb.SetFontAndSize(font, 12);
cb.ShowText("Hello World");
cb.EndText();
cb.BeginText();
cb.SetTextMatrix(100, 250);
cb.ShowText("Some other text");
cb.EndText();
doc.Close();
}
Use iTextSharp. Free.
#binaryhowl - You can try Syncfusion PDF. It is great component with excellent support
http://asp.syncfusion.com/sfaspnetsamplebrowser/9.1.0.20/Web/Pdf.Web/samples/4.0/