When I export ARABIC data into pdf.Microsoft adobereader showing error.Adobe reader could not open file because it is either not a supported file.My code is following asp.net c#.Guide me
protected void btnExport_Click(object sender, EventArgs e)
{
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment;filename=TestPage.pdf");
Document doc = new Document(PageSize.LETTER);
doc.Open();
//Sample HTML
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(#"<p>This is a test: <strong>مسندم</strong></p>");
//Path to our font
string arialuniTff = Server.MapPath("~/tradbdo.TTF");
//Register the font with iTextSharp
iTextSharp.text.FontFactory.Register(arialuniTff);
//Create a new stylesheet
iTextSharp.text.html.simpleparser.StyleSheet ST = new iTextSharp.text.html.simpleparser.StyleSheet();
//Set the default body font to our registered font's internal name
ST.LoadTagStyle(HtmlTags.BODY, HtmlTags.FACE, "Traditional Arabic Bold");
//Set the default encoding to support Unicode characters
ST.LoadTagStyle(HtmlTags.BODY, HtmlTags.ENCODING, BaseFont.IDENTITY_H);
//Parse our HTML using the stylesheet created above
List<IElement> list = HTMLWorker.ParseToList(new StringReader(stringBuilder.ToString()), ST);
//Loop through each element, don't bother wrapping in P tags
foreach (var element in list)
{
doc.Add(element);
}
doc.Close();
Response.Write(doc);
Response.End();
}
I found the following article which shows how to correctly export and display Arabic content via the iTextSharp library: http://geekswithblogs.net/JaydPage/archive/2011/11/02/using-itextsharp-to-correctly-display-hebrew--arabic-text-right.aspx.
Here is the code sample that you can try:
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.Text.RegularExpressions;
using System.IO;
using System.Diagnostics;
public void WriteDocument()
{
//Declare a itextSharp document
Document document = new Document(PageSize.A4);
//Create our file stream and bind the writer to the document and the stream
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(#"C:\Test.Pdf", FileMode.Create));
//Open the document for writing
document.Open();
//Add a new page
document.NewPage();
//Reference a Unicode font to be sure that the symbols are present.
BaseFont bfArialUniCode = BaseFont.CreateFont(#"C:\ARIALUNI.TTF", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
//Create a font from the base font
Font font = new Font(bfArialUniCode, 12);
//Use a table so that we can set the text direction
PdfPTable table = new PdfPTable(1);
//Ensure that wrapping is on, otherwise Right to Left text will not display
table.DefaultCell.NoWrap = false;
//Create a regex expression to detect hebrew or arabic code points
const string regex_match_arabic_hebrew = #"[\u0600-\u06FF,\u0590-\u05FF]+";
if (Regex.IsMatch("مسندم", regex_match_arabic_hebrew, RegexOptions.IgnoreCase))
{
table.RunDirection = PdfWriter.RUN_DIRECTION_RTL;
}
//Create a cell and add text to it
PdfPCell text = new PdfPCell(new Phrase("مسندم", font));
//Ensure that wrapping is on, otherwise Right to Left text will not display
text.NoWrap = false;
//Add the cell to the table
table.AddCell(text);
//Add the table to the document
document.Add(table);
//Close the document
document.Close();
//Launch the document if you have a file association set for PDF's
Process AcrobatReader = new Process();
AcrobatReader.StartInfo.FileName = #"C:\Test.Pdf";
AcrobatReader.Start();
}
The iTextSharp.text.Document is a class used to help bridge human concepts like Paragraph and Margin into PDF concepts. The bridge part is important. It is not a PDF file in any way so it should never be treated as a PDF. Doing so would be like treating System.Drawing.Graphics as if it were an image. This leads to one of your problems on the second to last line of code that tries to treat the Document as if it were a PDF by sending it directly to the output stream:
//This won't work
Response.Write(doc);
You will find many, many tutorials out there that do this and they are all wrong. Fortunately (or unfortunately), PDF is forgiving and allows junk data at the end so only a handful of PDF fail and people assume there was some other problem.
Your other problem is that you are missing a PdfWriter. If Document is the bridge, PdfWriter is the actual construction worker that puts that PDF together. It, however, is also not a PDF. Instead, it needs to be bound to a stream like a file, in-memory or the HttpResponse.OutputStream.
Below is some code that shows this off. I very strongly recommend separating your PDF logic from your ASPX logic. Do all of you PDF stuff first and get an actual "something" that represents a PDF, then do something with it.
At the beginning we declare a byte array that we'll fill in later. Next we create a System.IO.MemoryStream that will be used to write the PDF to. After creating the Document we then create a PdfWriter that's bound to the Document and our stream. Your internal code is the same and although I didn't test it it appears correct. Right before we're done with our MemoryStream we grab the active bytes into our byte array. Lastly we use the BinaryWrite() method to send our raw binary PDF to the requesting client.
//At the end of this bytes will hold a byte array representing an actual PDF file
Byte[] bytes;
//Create a simple in-memory stream
using (var ms = new MemoryStream()){
using (var doc = new Document()) {
//Create a new PdfWriter bound to our document and the stream
using (var writer = PdfWriter.GetInstance(doc, ms)) {
doc.Open();
//This is unchanged from the OP's code
//Sample HTML
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(#"<p>This is a test: <strong>مسندم</strong></p>");
//Path to our font
string arialuniTff = Server.MapPath("~/tradbdo.TTF");
//Register the font with iTextSharp
iTextSharp.text.FontFactory.Register(arialuniTff);
//Create a new stylesheet
iTextSharp.text.html.simpleparser.StyleSheet ST = new iTextSharp.text.html.simpleparser.StyleSheet();
//Set the default body font to our registered font's internal name
ST.LoadTagStyle(HtmlTags.BODY, HtmlTags.FACE, "Traditional Arabic Bold");
//Set the default encoding to support Unicode characters
ST.LoadTagStyle(HtmlTags.BODY, HtmlTags.ENCODING, BaseFont.IDENTITY_H);
//Parse our HTML using the stylesheet created above
List<IElement> list = HTMLWorker.ParseToList(new StringReader(stringBuilder.ToString()), ST);
//Loop through each element, don't bother wrapping in P tags
foreach (var element in list) {
doc.Add(element);
}
doc.Close();
}
}
//Right before closing the MemoryStream grab all of the active bytes
bytes = ms.ToArray();
}
//We now have a valid PDF and can do whatever we want with it
//In this case, use BinaryWrite to send it directly to the requesting client
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment;filename=TestPage.pdf");
Response.BinaryWrite(bytes);
Response.End();
Related
Is it possible to modify/remove the creation date in metadata? I'm looking to do something similar to this:
Overwrite creationDate in pdf using iText and pdf writer
EDIT:
I have tried the following methods:
writer.Info.Remove(PdfName.CREATIONDATE);
or
writer.Info.Put(PdfName.CREATIONDATE, new PdfDate(new DateTime(2017, 01, 01)));
where writer is a PdfWriter object.
However, that creates a copy of the object (a PdfDictionary) and doesn't modify the PDF I'm creating.
I also can't assign i.e. writer.Info = info
I tried following the advice given in the Java article.
I tried to do this:
var info = writer.Info;
stamper.MoreInfo = info
where stamper is a PdfStamper
But the types are incompatible and I don't think this would work. Does anyone know the actual methods to remove/modify the metadata?
EDIT 2:
Here is the code, I'm creating a new file from an existing PDF.
var filename = #"C:\Users\Someone\Documents\aPdf.pdf";
using( var output = new MemoryStream() )
{
Document document = new Document();
PdfCopy writer = new PdfCopy( document, output );
writer.CloseStream = false;
document.Open();
//read in PDF
PdfReader reader = new PdfReader(filename);
reader.ConsolidateNamedDestinations();
PdfImportedPage page = writer.GetImportedPage(reader, 1);
writer.AddPage(page);
reader.Close();
writer.Close();
document.Close();
return output.ToArray();
}
Now, when I open the file with a text editor this line is inserted (I need it constant/gone):
<</Producer(iTextSharp’ 5.5.12 ©2000-2017 iText Group NV \(AGPL-version\))/CreationDate(D:20180412155130+01'00')/ModDate(D:20180412155130+01'00')>>
The reason why we need to remove/set the date is that we're taking the MD5 hash of the file. Every time a new document is generated, that line changes leading to different MD5 hashes.
As I was trying to get a constant MD5 checksum for the generated file, I had to also set the ID constant, as mentioned by mkl.
My solution was to search byte array produced (i.e. the created PDF), and manually set the values to constants. The text is ASCII chars. I removed the /CreationDate and /ModifiedDated from the PDF entirely, and set the generated ID to a constant arbitrary value.
I' m using itextsharp to create pdf from template pdf file. But new pdf file is created like dynamic pdf. I want to convert this file to static pdf file, so i tried to use xfaworker. I get "Signature was corrupted" error from itextsharp.licensekey.dll. How can i use xfaworker or another dll for flatten dynamic pdf?
public string Create(FaxPDFModel model, MemoryStream ms)
{
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string templatePath = Path.GetDirectoryName(Uri.UnescapeDataString(uri.Path));
PdfReader pdfTemplate = new PdfReader(Path.Combine(Path.Combine(templatePath, "Docs"), "fax_template.pdf"));
PdfStamper stamper = new PdfStamper(pdfTemplate, ms);
stamper.Writer.CloseStream = false;
BaseFont bf = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, "ISO-8859-9", BaseFont.EMBEDDED);
var acroFields = stamper.AcroFields;
acroFields.GenerateAppearances = true;
stamper.FormFlattening = true;
acroFields.AddSubstitutionFont(bf);
acroFields.SetField("Name", "Mutabakat test");
acroFields.SetField("Title", "DANIŞMANLIK");
acroFields.SetField("Department", "test");
acroFields.SetField("Phone", "0 (212) 555 55 55");
stamper.Close();
string path = Path.Combine(Path.Combine(templatePath, "Docs"), System.Guid.NewGuid().ToString());
string pdfPath = path + ".pdf";
Document document = new Document();
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(pdfPath, FileMode.Create));
XFAFlattener xfaf = new XFAFlattener(document, writer);
ms.Position = 0;
xfaf.Flatten(new PdfReader(ms));
document.Close();
return pdfPath;
}
If you want to solve your problem, you will have to start by fixing the following errors:
1. You are using code to fill AcroForms instead of code to fill XFA forms:
If you have a dynamic XFA form, your PDF acts as a container for XML. This form doesn't expect data in the form of key value pairs. This form expects data stored as XML.
You can not use this code:
var acroFields = stamper.AcroFields;
acroFields.AddSubstitutionFont(bf);
acroFields.SetField("Name", "Mutabakat test");
acroFields.SetField("Title", "DANIŞMANLIK");
acroFields.SetField("Department", "test");
acroFields.SetField("Phone", "0 (212) 555 55 55");
This code expects that your form is an AcroForm. You need to fill the form like this:
AcroFields form = stamper.AcroFields;
XfaForm xfa = form.Xfa;
xfa.FillXfaForm(new FileStream(xml, FileMode.Open));
In this snippet xml refers to the data stored as XML.
2. You try to flatten the form before flattening the form:
I see this line in the first part of your code:
stamper.FormFlattening = true;
With this line, you remove all interactivity from your PDF. After closing the stamper object, you no longer have a form, hence the second part of your code will never work.
3. You are trying to embed a Standard Type 1 font:
This line doesn't make sense:
BaseFont bf = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, "ISO-8859-9", BaseFont.EMBEDDED);
Times-Roman is a Standard Type 1 font (in the old days, we called this a Base14 font); iText never embeds any of the 14 Standard Type 1 fonts defined for PDF, hence the parameter BaseFont.EMBEDDED will be ignored.
4. The real error:
XFA Worker is a closed source addon for iTextSharp. It requires a valid license key. When you get an error saying "Signature was corrupted", you are using a license key that is corrupt.
Possible causes:
You are not a customer of iText Group. You are using a key that you found somewhere and you changed some of its contents.
You are a customer of iText Group. You received a key, but somehow it got tampered with. In the past, we've had a similar problem where a customer was reading the key as if it was encoded in EBCDIC. Please contact your account manager at iText Group for more info.
i try to draw simple shapes (rectangles, circles..) on an existing PDF using ITextSharp, without having to create a new PDF. I found a post who talk about this issue (itextsharp modify existing pdf (no new source pdf) and add watermark) and i would like to know if anybody could tell me more about it.
my aim is to modify a pdf by adding a circle on it, the current solution involve the creation of a new PDF (Itextsharp). Is it possible to add a circle on a PDF without creating a new one ?
Thank you.
J.
You can't read a file and write to it simultaneously. Think of how Word works: you can't open a Word document and write directly to it. Word always creates a temporary file, writes the changes to it, then replaces the original file with it and then throws away the temporary file.
You can do that too:
read the original file with PdfReader,
create a temporary file for PdfStamper, and when you're done,
replace the original file with the temporary file.
Or:
read the original file into a byte[],
create PdfReader with this byte[], and
use the path to the original file for PdfStamper.
This second option is more dangerous, as you'll lose the original file if you do something that causes an exception in PdfStamper.
As for adding content with PdfStamper, please take a look at the section entitled "Manipulating existing PDFs" in the free ebook The Best iText Questions on StackOverflow. You'll find questions such as:
How to add a watermark to a PDF file?
How do I insert a hyperlink to another page with iTextSharp in an existing PDF?
iText - How to stamp image on existing PDF and create an anchor
...
All of these examples add content by creating a PdfContentByte instance like this:
PdfContentByte canvas = stamper.getOverContent(pagenumber);
It's this canvas you need to use when drawing a circle on the page with page number pagenumber. It is important that you use the correct coordinates when you do this. That's explained here: How to position text relative to page using iText?
Update:
Json posted the following code in the comments:
string oldFile = #"C:\Users\ae40394\Desktop\hello.pdf";
string newFile = #"C:\Users\ae40394\Desktop\NEW.pdf";
// creating a reader with the original PDF
PdfReader reader = new PdfReader(oldFile);
Rectangle rect = reader.GetPageSize(1);
FileStream fs = new FileStream(newFile,FileMode.Create);
using (PdfStamper stamper = new PdfStamper(reader, fs)) {
// modify the pdf content
PdfContentByte cb = stamper.GetOverContent(1);
cb.SetColorStroke(iTextSharp.text.BaseColor.GREEN);
cb.SetLineWidth(5f);
cb.Circle(rect.GetLeft() + 30, rect.GetBottom() + 30 ,20f);
cb.Stroke();
}
reader.Close();
File.Replace(#"C:\Users\ae40394\Desktop\NEW.pdf", #"C:\Users\ae40394\Desktop\hello.pdf", #"C:\Users\ae40394\Desktop\hello.pdf.bac");
I slightly adapted the code, because:
There is no need for a Document object,
The stamper is closed when using is closed,
When the stamper is closed, so is the FileStream
the coordinates of the circle were hard coded. I used the page size to make sure they are made relative to the origin of the coordinate system, although to be sure, you may also want to check if there's a Crop Box.
You CAN read a file and write to it simultaneously.
Here is an example:
private void button4_Click(object sender, EventArgs e)
{
using (PdfReader pdfReader = new PdfReader(new FileStream(pdfInput, FileMode.Open, FileAccess.Read, FileShare.Read)))
{
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(pdfInput, FileMode.Open, FileAccess.Write, FileShare.None)))
{
PdfContentByte canvas = pdfStamper.GetUnderContent(1);
canvas.SetColorFill(BaseColor.YELLOW);
canvas.Rectangle(36, 786, 66, 16);
canvas.Fill();
}
}
// PDF Datei im Anschluss anzeigen/öffnen
System.Diagnostics.Process.Start(pdfInput);
}
string oldFile = #"C:\...6166-21.pdf";
string newFile = #"C:\...NEW.pdf";
// open the reader
PdfReader reader = new PdfReader(oldFile);
Rectangle size = reader.GetPageSizeWithRotation(1);
Document document = new Document(size);
FileStream fs = new FileStream(newFile, FileMode.Create, FileAccess.Write);
PdfWriter writer = PdfWriter.GetInstance(document, fs);
document.Open();
// the pdf content
PdfContentByte cb = writer.DirectContent;
cb.SetColorStroke(iTextSharp.text.BaseColor.GREEN);
cb.Circle(150f, 150f, 50f);
cb.Stroke();
// create the new page and add it to the pdf
PdfImportedPage page = writer.GetImportedPage(reader, 1);
cb.AddTemplate(page, 0, 0);
// close the streams and voilá the file should be changed :)
document.Close();
fs.Close();
writer.Close();
reader.Close();
I want to create a pdf in which i have labels. eg: Name:_, City:__; and i want to fill blanks dynamically as per my studentID using fields.SetField("name", Convert.ToString(dsstudent.Tables[0].Rows[0]["Name"].ToString())); with asp.net c#.
The best option is iTextSharp, by far the easiest way to render pdf. You can use html templates and dinamically replace values or just render any webcontrol into a html string and save it as pdf.
You can have something like this
string html = "<h1>[PAGE_TITLE]<h1/>[STUDENTS]";
//get your values here
...
html = html.Replace("[PAGE_TITLE]", MyPageTitle);
html = html.Replace("[STUDENTS]", MyStudentsTableHtml);
Then with iTextSharp (Taken from https://web.archive.org/web/20211020001758/https://www.4guysfromrolla.com/articles/030911-1.aspx)
// Create a Document object
var document = new Document(PageSize.A4, 50, 50, 25, 25);
// Create a new PdfWriter object, specifying the output stream
var output = new MemoryStream();
var writer = PdfWriter.GetInstance(document, output);
// Open the Document for writing
document.Open();
var parsedHtmlElements = HTMLWorker.ParseToList(new StringReader(html), null);
foreach (var htmlElement in parsedHtmlElements)
{
document.Add(htmlElement as IElement);
}
document.Close();
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", String.Format("attachment;filename=students{0}.pdf", YourStudendsPrintingId));
Response.BinaryWrite(output.ToArray());
As you can see, with little tweaking from your side, you could create the PDF you need. One thing they don't say, iTextSharp is very picky with the html, it it finds some error on the html or don't like some old tag (say <HR>) it throws a pretty nasty exception that doesn't point to that kind of problem!!
I have an existing PDF document named as aa.pdf. This PDF document has 3 pages. I'd like to add a PDF form field (or a text) at the page bottom of the first page in aa.pdf using iTextSharp.
Meanwhile, I also hope that the PDF form field added (or the text added) can link into another page of aa.pdf. For example, after I click the PDF form field (or the text) located in the first page of aa.pdf,this PDF document skips into the second page.
How can I realize the aboved functionalities using iTextSharp?
Thanks.
To create links within a PDF you use a PdfAction which can be set on a Chunk which can optionally be added to a Paragraph. There are several different types of actions that you can choose from, the two that you are probably interested in are the NEXTPAGE action and/or the GotoLocalPage action. The first item does what it says and goes to the next page. This one is nice because you don't have to worry about figuring out what page number you are on. The second item allows you to specify the specific page number to go to. In its simplest form you can do:
Chunk ch = new Chunk("Go to next page").SetAction(new PdfAction(PdfAction.NEXTPAGE));
This creates a Chunk that you can add in whatever way you want. When working with an existing PDF there's several different ways to add text to a page. One way it to use a ColumnText object which has a method called SetSimpleColumn that allows you to define a simple rectangle that you can add elements to.
Lastly, PDF readers don't automatically treat links differently within a PDF except to give a different cursor when hovering. More specifically, unlike a webpage where hyperlinks are turned a different color, PDFs don't change the color of links unless you tell them to, so this should be kept in mind when creating them. Also, when modifying a PDF you generally never want to overwrite the existing PDF during the process because that would be writing to something that your reading from. Sometimes it works, more often then not it breaks, sometimes subtly. Instead, write to a second file and when you are completely done, erase the first file and rename the second file.
The code below is a full working C# 2010 WinForms app targeting iTextSharp 5.1.2.0. The first part of the code creates a sample PDF called "aa.pdf" on the desktop. If you already have that file you can comment this section out but its in here so others can reproduce this example. The second part creates a new file called "bb.pdf" based on "aa.pdf". It adds two text links to the bottom of the first page. The first link advances the PDF to just the next page while the second link advances the PDF to a specific page number. See the comments in the code for specific implementation details.
using System;
using System.IO;
using System.Windows.Forms;
using iTextSharp.text;
using iTextSharp.text.pdf;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
//Files that we'll be working with
string inputFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "aa.pdf");
string outputFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "bb.pdf");
//Create a standard PDF to test with, nothing special here
using (FileStream fs = new FileStream(inputFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (Document doc = new Document(PageSize.LETTER)) {
using (PdfWriter writer = PdfWriter.GetInstance(doc, fs)) {
doc.Open();
//Create 10 pages with labels on each page
for (int i = 1; i <= 10; i++) {
doc.NewPage();
doc.Add(new Paragraph(String.Format("This is page {0}", i)));
}
doc.Close();
}
}
}
//For the OP, this is where you would start
//Declare some variables to be used later
ColumnText ct;
Chunk c;
//Bind a reader to the input file
PdfReader reader = new PdfReader(inputFile);
//PDFs don't automatically make hyperlinks a special color so we're specifically creating a blue font to use here
iTextSharp.text.Font BlueFont = FontFactory.GetFont("Arial", 12, iTextSharp.text.Font.NORMAL, iTextSharp.text.BaseColor.BLUE);
//Create our new file
using (FileStream fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
//Bind a stamper to our reader and output file
using (PdfStamper stamper = new PdfStamper(reader, fs)) {
Chunk ch = new Chunk("Go to next page").SetAction(new PdfAction(PdfAction.NEXTPAGE));
//Get the "over" content for page 1
PdfContentByte cb = stamper.GetOverContent(1);
//This example adds a link that goes to the next page
//Create a ColumnText object
ct = new ColumnText(cb);
//Set the rectangle to write to
ct.SetSimpleColumn(0, 0, 200, 20);
//Add some text and make it blue so that it looks like a hyperlink
c = new Chunk("Go to next page", BlueFont);
//Set the action to go to the next page
c.SetAction(new PdfAction(PdfAction.NEXTPAGE));
//Add the chunk to the ColumnText
ct.AddElement(c);
//Tell the system to process the above commands
ct.Go();
//This example add a link that goes to a specific page number
//Create a ColumnText object
ct = new ColumnText(cb);
//Set the rectangle to write to
ct.SetSimpleColumn(200, 0, 400, 20);
//Add some text and make it blue so that it looks like a hyperlink
c = new Chunk("Go to page 3", BlueFont);
//Set the action to go to a specific page number. This option is a little more complex, you also have to specify how you want to "fit" the document
c.SetAction(PdfAction.GotoLocalPage(3, new PdfDestination(PdfDestination.FIT), stamper.Writer));
//Add the chunk to the ColumnText
ct.AddElement(c);
//Tell the system to process the above commands
ct.Go();
}
}
this.Close();
}
}
}