saving modified data in pdf itextsharp - itext

I have created a pdf using itextsharp which contains some editable fields, when the service is called the pdf is created. But the problem what I am facing is, if i am changing anything in the pdf and downloading it then the changes are not saved. Also i want to open the pdf in a new tab through server side.
Code what I am using is:
public static String[] LANGUAGES_gc = { "English", "Math", "Science" };
[HttpGet]
[ODataRoute("GetPdf")]
public void DownloadPDF()
{
HttpContext.Current.Response.ContentType = "application/pdf";
HttpContext.Current.Response.AddHeader("content-disposition", "inline;filename=Example.pdf");
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
Document doc = new Document(iTextSharp.text.PageSize.A4, 10f, 10f, 100f, 0f);
string pdfFilePath = HttpContext.Current.Server.MapPath(".") + "/PDFFiles";
PdfWriter wri = PdfWriter.GetInstance(doc, HttpContext.Current.Response.OutputStream);
doc.Open();
doc.AddAuthor("Test author");
doc.AddCreationDate();
PdfContentByte cb = wri.DirectContent;
Font _bf = new Font(Font.FontFamily.HELVETICA, 6);
PdfFormField _radioGroup = PdfFormField.CreateRadioButton(wri, true);
_radioGroup.FieldName = "language_gc";
Rectangle _rect;
RadioCheckField _radioG;
PdfFormField _radioField1;
PdfFormField field;
for (int i = 0; i < LANGUAGES_gc.Length; i++)
{
_rect = new Rectangle(46, 806 - i * 40, 60, 788 - i * 40);
_radioG = new RadioCheckField(wri, _rect, null, LANGUAGES_gc[i]);
_radioG.BackgroundColor = new GrayColor(0.8f);
_radioG.BorderColor = GrayColor.BLACK;
_radioG.CheckType = RadioCheckField.TYPE_CIRCLE;
_radioField1 = _radioG.RadioField;
_radioGroup.AddKid(_radioField1);
ColumnText.ShowTextAligned(cb, Element.ALIGN_LEFT, new Phrase(LANGUAGES_gc[i], new Font(Font.FontFamily.HELVETICA, 18)), 70, 790 - i * 40, 0);
}
/* Button */
_rect = new Rectangle(300, 806, 370, 788);
PushbuttonField button = new PushbuttonField(wri, _rect, "Buttons");
button.BackgroundColor = new GrayColor(0.75f);
button.BorderColor = GrayColor.GRAYBLACK;
button.BorderWidth = 1;
button.BorderStyle = PdfBorderDictionary.STYLE_BEVELED;
button.TextColor = GrayColor.GRAYBLACK ;
button.FontSize = 12;
button.Text = "Submit";
//button.Layout = PushbuttonField.LAYOUT_ICON_LEFT_LABEL_RIGHT;
button.ScaleIcon = PushbuttonField.SCALE_ICON_ALWAYS;
button.ProportionalIcon = true;
button.IconHorizontalAdjustment = 0;
field = button.Field;
field.Action = PdfAction.JavaScript("this.showButtonState()", wri);
wri.AddAnnotation(field);
//}
//return ms.ToArray();
/*----------------------------------------------------*/
wri.AddAnnotation(_radioGroup);
wri.AddAnnotation(button.Field);
cb = wri.DirectContent;
doc.Close();
HttpContext.Current.Response.Write(doc);
HttpContext.Current.Response.End();
}
Can someone suggest me the solution??

Let's make an analogy here, with a simpler file-type. Suppose you're showing the user a textfile. They open it in their native .txt app (notepad) and make some changes.
Do you expect their changes to be communicated automatically back to your server?
Or that their changes are magically propagated? Of course not.
And even if it would, this seems like functionality notepad would have to provide, rather than something the creator of the file should do.
Now, as it so happens, there is a particular standard of pdf documents that exists for precisely your use-case. Essentially, the document sets up a connection to a server, and synchronizes. However, this standard is rather obscure, not a lot of viewers support it.
To the best of my knowledge, no pdf library (including iText) supports making documents like that.

Related

iText Pdf Merging Checkbox Issue

We are using iText Pdf API version 5.5.3 and we are trying to merge pdf documents which sometimes contain checkboxes , we write pdf document in servlet output stream and displays in iframe.
It works well in IE(tried in 11) but checkbox doesn't appear in Chrome(tried in 52).
Below is the sample code we use to display PDF.
InputStream in = docFile.getImage()
.getBinaryStream();
reader = new PdfReader(in);
pdfReaderList.add(reader);
document = new Document(PageSize.A4);
byteArrayOutputStream = new ByteArrayOutputStream();
PdfCopy copy = new PdfCopy(document, byteArrayOutputStream);
document.setMargins(35, 35, 48, 75);
document.open();
copy.setMargins(35, 35, 48, 75);
// add a document
Iterator<PdfReader> pdfReader = pdfReaderList.iterator();
while (pdfReader.hasNext()){
PdfImportedPage page;
reader = MCPDFFileWriter.unlockPdf(pdfReader.next());
for (int currentPage = 1; currentPage <= reader.getNumberOfPages(); currentPage++) {
page = copy.getImportedPage(reader, currentPage);
pageNum++;
copy.addPage(page);
footerNamesList.add(fileName);
footerMap.put(footerMap.size() + 1, fileName);
}
}
document.close ();
reader.close();
copy.close();
I also gone through this Link and given solution seems to be working when I use below code -
InputStream in = docFile.getImage()
.getBinaryStream();
reader = new PdfReader(in);
pdfReaderList.add(reader);
document = new Document(PageSize.A4);
byteArrayOutputStream = new ByteArrayOutputStream();
PdfCopy copy = new PdfCopy(document, byteArrayOutputStream);
document.setMargins(35, 35, 48, 75);
document.open();
copy.setMargins(35, 35, 48, 75);
**copy.setMergeFields();**
// add a document
**copy.addDocument(reader);**
document.close ();
reader.close();
copy.close();
However I sometimes face OutOfMemoryError and looking for some idea if there is any known issue with copy.setMergeFields();copy.addDocument(reader); and how it can be overcome ?
A bug was also reported in chrome ( in the thought of plugin issue) and sample pdf are attached there

iText Text Expansion Not Working in Certain Conditions

The following code will generate a pdf that will not use the specified text expansions when read out loud. It seems that adding the image in a container is causing the problem.
void Main()
{
using(var ms = new MemoryStream())
{
var doc = new Document(PageSize.LETTER, 72, 72, 72, 72);
var writer = PdfWriter.GetInstance(doc, ms);
writer.SetTagged();
doc.Open();
var c1 = new Chunk("ABC");
c1.SetTextExpansion("the alphabet");
var p1 = new Paragraph();
p1.Add(c1);
doc.Add(p1);
// Adding this image to the document as img > chunk > doc causes the text expansion not to work.
// Adding this image to the document as img > doc works
var t = writer.DirectContent.CreateTemplate(6, 6);
t.SetLineWidth(1f);
t.Circle(3f, 3f, 1.5f);
t.SetGrayFill(0);
t.FillStroke();
var i = iTextSharp.text.Image.GetInstance(t);
var c2 = new Chunk(i, 0, 0);
doc.Add(c2);
var c3 = new Chunk("foobar");
c3.SetTextExpansion("foo bar");
var p3 = new Paragraph();
p3.Add(c3);
doc.Add(p3);
doc.Close();
ms.Flush();
File.WriteAllBytes("d:\\expansion.pdf", ms.ToArray());
}
}
Is this just me doing something wrong or a bug?
While this doesn't read out loud correctly in Adobe Reader, it does in JAWS. So it sounds like this is a reader issue and not necessarily an iText issue.

iTextSharp does not render header/footer when using element generated by XmlWorkerHelper

I am trying to add header/footer to a PDF whose content is otherwise generated by XMLWorkerHelper. Not sure if it's a placement issue but I can't see the header/footer.
This is in an ASP.NET MVC app using iTextSharp and XmlWorker packages ver 5.4.4 from Nuget.
Code to generate PDF is as follows:
private byte[] ParseXmlToPdf(string html)
{
XhtmlToListHelper xhtmlHelper = new XhtmlToListHelper();
Document document = new Document(PageSize.A4, 30, 30, 90, 90);
MemoryStream msOutput = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(document, msOutput);
writer.PageEvent = new TextSharpPageEventHelper();
document.Open();
var htmlContext = new HtmlPipelineContext(null);
htmlContext.SetTagFactory(Tags.GetHtmlTagProcessorFactory());
var cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(false);
cssResolver.AddCssFile(HttpContext.Server.MapPath("~/Content/themes/mytheme.css"), true);
var pipeline = new CssResolverPipeline(cssResolver, new HtmlPipeline(htmlContext, new PdfWriterPipeline(document, writer)));
var worker = new XMLWorker(pipeline, true);
var parser = new XMLParser();
parser.AddListener(worker);
using (TextReader sr = new StringReader(html))
{
parser.Parse(sr);
}
//string text = "Some Random Text";
//for (int k = 0; k < 8; ++k)
//{
// text += " " + text;
// Paragraph p = new Paragraph(text);
// p.SpacingBefore = 8f;
// document.Add(p);
//}
worker.Close();
document.Close();
return msOutput.ToArray();
}
Now instead of using these three lines
using (TextReader sr = new StringReader(html))
{
parser.Parse(sr);
}
if I comment them out and uncomment the code to add a random Paragraph of text (commented in above sample), I see the header/footer along with the random text.
What am I doing wrong?
The EventHandler is as follows:
public class TextSharpPageEventHelper : PdfPageEventHelper
{
public Image ImageHeader { get; set; }
public override void OnEndPage(PdfWriter writer, Document document)
{
float cellHeight = document.TopMargin;
Rectangle page = document.PageSize;
PdfPTable head = new PdfPTable(2);
head.TotalWidth = page.Width;
PdfPCell c = new PdfPCell(ImageHeader, true);
c.HorizontalAlignment = Element.ALIGN_RIGHT;
c.FixedHeight = cellHeight;
c.Border = PdfPCell.NO_BORDER;
head.AddCell(c);
c = new PdfPCell(new Phrase(
DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") + " GMT",
new Font(Font.FontFamily.COURIER, 8)
));
c.Border = PdfPCell.TOP_BORDER | PdfPCell.RIGHT_BORDER | PdfPCell.BOTTOM_BORDER | PdfPCell.LEFT_BORDER;
c.VerticalAlignment = Element.ALIGN_BOTTOM;
c.FixedHeight = cellHeight;
head.AddCell(c);
head.WriteSelectedRows(
0, -1, // first/last row; -1 flags all write all rows
0, // left offset
// ** bottom** yPos of the table
page.Height - cellHeight + head.TotalHeight,
writer.DirectContent
);
}
}
Feeling angry and stupid for having lost more than two hours of my life to Windows 8.1! Apparently the built in PDF Reader app isn't competent enough to show 'Headers'/'Footers'. Installed Foxit Reader and opened the output and it shows the Headers allright!
I guess I should try with Adobe Reader too!!!
UPDATES:
I tried opening the generated PDF in Adobe Acrobat reader and finally saw some errors. This made me look at the HTML that I was sending to the XMLWorkerHelper more closely. The structure of the HTML had <div>s inside <table>s and that was tripping up the generated PDF. I cleaned up the HTML to ensure <table> inside <table> and thereafter the PDF came out clean in all readers.
Long story short, the code above is fine, but if you are testing for PDF's correctness, have Adobe Acrobat Reader handy at a minimum. Other readers behave unpredictably as in either not reporting errors or incorrectly rendering the PDF.

using iTextSharp.ShowTextAligned() to add watermark

We want to add a water mark with user email & name on top of our pdf before we send it. I've written code that does that and it is working great. I want to check if this is the best way of doing this. We want the water mark to be split into two lines at the top of the pdf.
, I used "ShowTextAligned()" twice with different "y" coordinates to achieve that.
private MemoryStream StampPdf(string pdfPath, string name, string email)
{
var memoryStream = new MemoryStream();
var reader = new PdfReader(pdfPath);
var pageCount = reader.NumberOfPages;
var stamper = new PdfStamper(reader, memoryStream);
var textAngle = 0;
var fontSize = 14;
var font = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.WINANSI, BaseFont.EMBEDDED);
var watermarkLine1 = "Personal use only for " + name;
var watermarkLine2 = "at " + email;
using (stamper)
{
for (var i = 1; i <= pageCount; i++)
{
var mediaBox = reader.GetPageSize(i);
var overContent = stamper.GetOverContent(i);
overContent.BeginText();
overContent.SetColorFill(BaseColor.RED);
overContent.SetFontAndSize(font, fontSize);
overContent.ShowTextAligned(PdfContentByte.ALIGN_LEFT, watermarkLine1, 10, mediaBox.Top - 20, textAngle);
overContent.ShowTextAligned(PdfContentByte.ALIGN_LEFT, watermarkLine2, 10, mediaBox.Top - 40, textAngle);
overContent.EndText();
}
}
reader.Close();
stamper.Close();
return memoryStream;
}
I want to confirm two things:
"Is it possible to use ShowTextAligned() to wrap text that reaches the end of the line?"
"Does ShowTextAligned() honor carriage return/newline?"
Thanks,
-Samah
Answer to question 1.: No, you need the ColumnText object to do that.
Answer to question 2.: No, showTextAligned() ignores newline characters.

iText - Strange column- / page changing behaviour with ColumnText

I am quite new to iText and trying to accomplish the following:
read a list of text files from local hd
arrange the texts of the files in a 2-column layout pdf file
add a consecutively numbered index before each text
I started with the MovieColumns1 example (http://itextpdf.com/examples/iia.php?id=64) and ended up with the following code:
final float[][] COLUMNS_COORDS = { { 36, 36, 296, 806 }, { 299, 36, 559, 806 } };
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document, resultFile);
document.open();
ColumnText ct = new ColumnText(writer.getDirectContent());
ct.setSimpleColumn(COLUMNS_COORDS[0][0], COLUMNS_COORDS[0][1],
COLUMNS_COORDS[0][2], COLUMNS_COORDS[0][3]);
File textDir = new File("c:/Users/raddatz/Desktop/123/texts/");
File[] files = textDir.listFiles();
int i = 1;
int column = 0;
for (File file : files) {
String text = FileUtils.readFileToString(file, "UTF-8");
float yLine = ct.getYLine();
System.out.println("adding '" + file.getName() + "'");
PdfPCell theText = new PdfPCell(new Phrase(text, new Font(Font.HELVETICA, 10)));
theText.setBorder(Rectangle.NO_BORDER);
theText.setPaddingBottom(10);
PdfPCell runningNumber = new PdfPCell(new Phrase(new DecimalFormat("00").format(i++), new Font(
Font.HELVETICA, 14, Font.BOLDITALIC,
new Color(0.7f, 0.7f, 0.7f))));
runningNumber.setBorder(Rectangle.NO_BORDER);
runningNumber.setPaddingBottom(10);
PdfPTable table = new PdfPTable(2);
table.setWidths(new int[] { 12, 100 });
table.addCell(runningNumber);
table.addCell(theText);
ct.addElement(table);
int status = ct.go(true);
if (ColumnText.hasMoreText(status)) {
column = Math.abs(column - 1);
if (column == 0) {
document.newPage();
System.out.println("inserting new page with size :" + document.getPageSize());
}
ct.setSimpleColumn(
COLUMNS_COORDS[column][0], COLUMNS_COORDS[column][1],
COLUMNS_COORDS[column][2], COLUMNS_COORDS[column][3]);
yLine = COLUMNS_COORDS[column][3];
System.out.println("correcting yLine to: " + yLine);
} else {
ct.addElement(table);
}
ct.setYLine(yLine);
System.out.println("before adding: " + ct.getYLine());
status = ct.go(false);
System.out.println("after adding: " + ct.getYLine());
System.out.println("--------------------------------");
}
document.close();
Here you can see the result:
http://d.pr/f/NEmx
Looking at the first page of the resulting PDF I assumed everything was working out fine.
But on second page you can see the problem(s):
text #31 is not displayed completely (first line + index is cut / not in visible area)
text #46 is not displayed completely (first three lines + index is cut / not in visible area)
On page 3 everything seems to be ok again. I am really lost here.
-- UPDATE (2013-03-14) --
I have analyzed the contents of the PDF now. The problem is not that content is show in non-visible areas but that the content is not present in the pdf at all. The missing part of the content is exactly the one which would have fit in the previous column / page. So it seems like ColumnText.go(true) is manipulating the object passed by addElement() before. Can someone confirm this? If so: what can I do about it?
-- end UPDATE (2013-03-14) --
Looking forward to your reply
regards,
sven
Solved! As soon as ColumnText indicates a table will not fit the current column I reinitialize ct with a new instance of ColumnText and add the table again.
In other words:
Each instance of ColumnText is exactly dealing one column of my document.
if (ColumnText.hasMoreText(status) || mediaPoolSwitch) {
column = Math.abs(column - 1);
if (mediaPoolSwitch) {
currentMediaPool = mediapool;
column = 0;
}
if (column == 0) {
document.newPage();
writeTitle(writer.getDirectContent(), mediapool.getName());
}
ct = new ColumnText(writer.getDirectContent());
ct.addElement(table);
ct.setSimpleColumn(
COLUMNS_COORDS[column][0], COLUMNS_COORDS[column][1],
COLUMNS_COORDS[column][2], COLUMNS_COORDS[column][3]);
yLine = COLUMNS_COORDS[column][3];
LOG.debug("correcting yLine to: " + yLine);
} else {
ct.addElement(table);
}
ct.setYLine(yLine);
ct.go();