How to add your data-properties (meta data) to PDF (iTextSharp) - c#

I convert the file to PDF using iTextSharp
Creating a new Document and inserting an image into it. How can I transfer width and height of a image to a new pdf? (because the image is compressed)
In the new Document, you can pass the title, keywords, etc. But if you need somewhere to store the old width and height (since the image is compressed), and when reading the PDF to the size of the old pictures. Each page has its own data.

This solution helped. Info contains metadata.
using (var writer = PdfWriter.GetInstance(doc, fs))
{
PdfDictionary info = writer.Info;
PdfName newData = new PdfName($"NewData");
info.Put(newData, new PdfString("any string data"));
}

Related

iTextSharp replace image with another PDF

I have a PDF file with some images, which I want to replace with some other PDF. The code goes through the pdf and gets the image references:
PdfDocument pdf = new PdfDocument(new PdfReader(args[0]), new PdfWriter(args[1]));
for(int i=1; i<=pdf.GetNumberOfPages(); ++i)
{
PdfDictionary pageDict = pdf.GetPage(i).GetPdfObject();
PdfDictionary resources = pageDict.GetAsDictionary(PdfName.Resources);
PdfDictionary xObjects = resources.GetAsDictionary(PdfName.XObject);
foreach (PdfName imgRef in xObjects.KeySet())
{
// image reference
}
}
For all my images I have a corresponding PDF which I would like to replace the image with. What I tried is to Put the other PDF (which is always a single page) as object by:
PdfDocument other = new PdfDocument(new PdfReader("replacement.pdf"));
xObjects.Put(imgRef, other.GetFirstPage().GetPdfObject().Clone());
But while closing the PdfDocument an exception is thrown:
iText.Kernel.PdfException: 'Pdf indirect object belongs to other PDF document. Copy object to current pdf document.'
How can I achieve to replace the image with (the content of) another PDF?
Update
I also tried a few other approaches, which maybe improved results. To overcome the previous error message, I copy the page to the original pdf by:
var page = other.GetFirstPage().CopyTo(pdf);
However, replacing the xObject doesn't work:
xObjects.Put(imgRef, page.GetPdfObject());
Results in a corrupted PDF.
To just copy the original page into another document to be used as an image replacement, you can use PdfPage#CopyAsFormXObject.
So let's assume we have this PDF as a template and we want to replace the image of a desert with the contents of another PDF:
Let's also assume the PDF that we want to use as a replacement looks as follows:
The issue is that if we blindly replace the original image with the contents of the PDF, chances are we will get something like this:
So we will get a feeling that everything worked well while we still have a bad visual result. The issue is that coordinates work a bit differently for plain raster images and vector XObjects (PDF replacements). So we also need to adjust the transformation matrix (/Matrix key) of our newly created XObject.
So the code could look like this:
PdfDocument pdf = new PdfDocument(new PdfReader(#"template.pdf"), new PdfWriter(#"out.pdf"));
for(int i=1; i<=pdf.GetNumberOfPages(); ++i) {
PdfDictionary pageDict = pdf.GetPage(i).GetPdfObject();
PdfDictionary resources = pageDict.GetAsDictionary(PdfName.Resources);
PdfDictionary xObjects = resources.GetAsDictionary(PdfName.XObject);
IDictionary<PdfName, PdfStream> toReplace = new Dictionary<PdfName, PdfStream>();
foreach (PdfName imgRef in xObjects.KeySet()) {
PdfStream previousXobject = xObjects.GetAsStream(imgRef);
PdfDocument imageReplacementDoc =
new PdfDocument(new PdfReader(#"insert.pdf"));
PdfXObject imageReplacement = imageReplacementDoc.GetPage(1).CopyAsFormXObject(pdf);
toReplace[imgRef] = imageReplacement.GetPdfObject();
adjustXObjectSize(imageReplacement);
imageReplacementDoc.Close();
}
foreach (var x in toReplace) {
xObjects.Put(x.Key, x.Value);
}
}
pdf.Close();
UPD: Implementation of adjustXObjectSize(thanks mkl):
private void adjustXObjectSize(PdfXObject pageXObject) {
float scaleXobject = 1 / Math.Max(pageXObject.GetWidth(), pageXObject.GetHeight());
AffineTransform transform = new AffineTransform();
transform.Scale(scaleXobject, scaleXobject);
float[] matrix = new float[6];
transform.GetMatrix(matrix);
pageXObject.GetPdfObject().Put(PdfName.Matrix, new PdfArray(matrix));
}
And the visual result after running the above code on the samples I described would look like this:

save as iText.Layout.Element.Image in folder

i want to save pdf page as image but no success. i am able to create iText.Layout.Element.Image from pdf with itext7 but stuck here
using var pdfreader = new PdfReader("../../../documents/valid.pdf");
PdfDocument origPdf = new PdfDocument(pdfreader);
PdfPage origPage = origPdf.GetPage(1);
using var stream = new MemoryStream();
using var pdfwriter = new PdfWriter(stream);
PdfDocument pdf = new PdfDocument(pdfwriter);
Document document = new Document(pdf);
PdfFormXObject pageCopy = origPage.CopyAsFormXObject(pdf);
Image image = new Image(pageCopy);
// want to save this image
The iText 7 Image class is (according to JavaDocs) a layout element that represents an image for inclusion in the document model. It essentially can wrap arbitrary contents to be added to the contents of some page (or form XObject, ...) in an image like manner. It is not, however, an arbitrary-content-to-bitmap converter.
If you want to render a page as a bitmap using iText 7 components, consider using the iText 7 Core add-on pdfRender.

Xamarin.Forms itext7 - There is no associate PdfWriter for making indirects

I am using itext7 to get the Stream of the file and fill in the form fields.
Here is my code:
using (MemoryStream outFile = new MemoryStream())
{
var streamFile = await App.GraphClient.Me.Drive.Items[item.Id].Content.Request().GetAsync();
using (PdfDocument pdf = new PdfDocument(new PdfReader(streamFile)))
{
PdfAcroForm form = PdfAcroForm.GetAcroForm(pdf, true);
IDictionary<String, PdfFormField> fields = form.GetFormFields();
PdfFormField toSet;
fields.TryGetValue("Full_Names", out toSet);
toSet.SetValue(Customer_Name.Text);
form.FlattenFields();
pdf.Close();
}
}
But I get an error on this line: toSet.SetValue(Customer_Name.Text); when trying to set the value, the error is:
There is no associate PdfWriter for making indirects.
My question is what am I doing wrong and how do I fix this? I am getting the file from OneDrive using Microsoft Graph API. The IDictionary of fields is getting populated and the name of field I am trying to set the value for is accurate.
The problem with your code is that you have dedicated outFile stream for the output result (the document with flattened fields) but you are not telling iText anything about that desired output destination.
PdfDocument has several constructors and the one you are using is PdfDocument(PdfReader) and it is dedicated for reading the document, not changing it (and setting a value is considered changing the document of course). So you should use PdfDocument(PdfReader, PdfWriter) constructor to provide the source document and the target destination to iText.
You should create your PdfDocument as follows:
PdfDocument pdf = new PdfDocument(new PdfReader(streamFile), new PdfWriter(outFile))
At the end of the execution, your outFile stream will contain the bytes of the resultant document.

Drawing on PDF using ITextSharp, without creating a new PDF

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();

Export arabic data into pdf asp.net showing error

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();

Categories

Resources