I want to change existing font style regular to bold, increase font size. Like if font style is regular I want to change it to bold. If font size 10 then i want to increase or decrease one size it(10->11 or 10->9)
After searching on this topic I found this code but this gives only the information of font and it doesn't change style and size
string OutputFile = "font.pdf";
//PdfReader pdfReader = new PdfReader(strFile);
PdfReader pdfReader = new PdfReader(mStream.ToArray());
//Get first page,Generally we get font information on first page,however we can loop throw pages e.g for(int i=0;i<=pdfReader.NumberOfPages;i++)
PdfDictionary cpage = pdfReader.GetPageN(1);
if (cpage == null)
return;
PdfDictionary dictFonts = cpage.GetAsDict(PdfName.RESOURCES).GetAsDict(PdfName.FONT);
if (dictFonts != null)
{
foreach (var font in dictFonts)
{
var dictFontInfo = dictFonts.GetAsDict(font.Key);
if (dictFontInfo != null)
{
//Get the font name-optional code
var baseFont = dictFontInfo.Get(PdfName.BASEFONT);
string strFontName = System.Text.Encoding.ASCII.GetString(baseFont.GetBytes(), 0, baseFont.Length);
//var bf = BaseFont.CreateFont((PRIndirectReference)baseFont);
//iTextSharp.text.Font exFont =new iTextSharp.text.Font(bf,20f);
//Remove the current font
//dictFontInfo.Remove(PdfName.BASEFONT);
//Set new font eg. Braille, Areal etc
//dictFontInfo.Put(PdfName.BASEFONT, new PdfString("Braille"));
}
}
}
//Now create a new document with updated font
using (FileStream FS = new FileStream(OutputFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
using (Document Doc = new Document())
{
using (PdfCopy writer = new PdfCopy(Doc, FS))
{
Doc.Open();
for (int j = 1; j <= pdfReader.NumberOfPages; j++)
{
writer.AddPage(writer.GetImportedPage(pdfReader, j));
}
Doc.Close();
}
}
}
pdfReader.Close();
i want also to change some font like Arial to some other font.
Changing the font of an existing PDF can not be done in a meaningful, generic way, without risk of messing up the layout.
To illustrate, assume you have the following text.
I'm using | to indicate a page-boundary.
Lorem Ipsum Dolor |
Sit Amet Consectetur|
Nunc |
If I make this text larger, or make it bold, or even italic, it is likely to take up more space. That means the word 'Consectetur' will no longer fit on the line.
PDF (unlike a Word document) does not automatically re-flow its content. The content would simply appear to go over the page boundary (and depending on the viewer you are using it might vanish).
The real problem is that the PDF format does not have the same information as the word format.
where are word-boundaries located?
where are paragraph boundaries?
(what language is this text being written in?)
All of these are important when performing layout for a document. And none of these are naturally present in a PDF document.
Related
I have created a signed PDF using iTextSharp in C# .Net.
In the signed PDF I want to have a validity symbol so that when a user opens it in Adobe Reader it shows a green tick mark along with its signature.
But in my web application (a html page with canvas) I want to remove that question mark from the PDF so that it does not show like in this screen:
So I want to keep the original bytes of the PDF in which signatureappearance.Acro6Layers = false; is added in code to get this symbol. But before showing it in my viewer (html page with canvas) I want to modify bytes and remove this yellow mark, so that it does not show "Signature Not Verified".
I have no experiences with the Aspose PDF-to-image rendering, but it looks like it probably simply renders the signature appearance as it is in the PDF. This, by the way, would be the correct thing to do.
As the extra layers from before Acrobat 6 are all drawn in the signature appearance in the saved file, you have to clear them. You can do that like this:
using (PdfReader pdfReader = new PdfReader(source))
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(dest, FileMode.Create, FileAccess.Write), '\0', true))
{
AcroFields fields = pdfStamper.AcroFields;
List<string> names = fields.GetSignatureNames();
foreach (string name in names)
{
PdfDictionary normal = PdfReader.GetPdfObject(fields.GetNormalAppearance(name)) as PdfDictionary;
PdfDictionary frm = normal?.GetAsDict(PdfName.RESOURCES)?.GetAsDict(PdfName.XOBJECT)?.GetAsStream(PdfName.FRM);
PdfDictionary frmResources = frm?.GetAsDict(PdfName.RESOURCES);
PdfDictionary frmXobjectResources = frmResources?.GetAsDict(PdfName.XOBJECT);
if (frmXobjectResources != null)
{
Console.WriteLine("Found XObject resources of FRM XObject");
clearLayer(pdfStamper.Writer, frmXobjectResources, PdfName.N1);
clearLayer(pdfStamper.Writer, frmXobjectResources, PdfName.N3);
clearLayer(pdfStamper.Writer, frmXobjectResources, PdfName.N4);
pdfStamper.MarkUsed(frmXobjectResources);
pdfStamper.MarkUsed(frmResources);
pdfStamper.MarkUsed(frm);
}
}
}
with this helper method:
void clearLayer(PdfWriter writer, PdfDictionary frmXobjectResources, PdfName layerName)
{
PdfStream existingLayer = frmXobjectResources.GetAsStream(layerName);
if (existingLayer != null)
{
PdfArray bBox = existingLayer.GetAsArray(PdfName.BBOX);
PdfTemplate newLayer = PdfTemplate.CreateTemplate(writer, 0, 0);
newLayer.BoundingBox = PdfReader.GetNormalizedRectangle(bBox);
frmXobjectResources.Put(layerName, newLayer.IndirectReference);
}
}
In different renderers the signature appearance of your original example document and the document resulting from the above code appear as follows:
an "as is" renderer (I used Chrome):
Acrobat 9.5 (German locale) not trusting your issuer
Acrobat DC trusting your issuer
A word of warning, though: In case of documents with certification signatures, not merely approval signatures, in particular with certification signatures with no changes allowed, Acrobat most likely will not like the result.
I have to add (register, embed) font to a PDF programmatically.
I tried with a lot of utilities like ghostscript or itextsharp but i did not manage to solve the problem.
For example in a situation like this one:
I would like to add Courier-Bold and get this situation:
I just created a project using iTextSharp v5.5.9 via NuGet and used the following code:
const string PdfLocation = #"C:\fakepath\output.pdf";
static void Main(string[] args)
{
using (var pdfDoc = new Document())
using (var fs = new FileStream(PdfLocation, FileMode.OpenOrCreate))
using (var writer = PdfWriter.GetInstance(pdfDoc, fs))
{
pdfDoc.Open();
var font = FontFactory.GetFont(FontFactory.COURIER_BOLD);
// Doesn't use font
var paragraph = new Paragraph("LINE 1");
paragraph.Font = font;
pdfDoc.Add(paragraph);
// Doesn't use font
var paragraph2 = new Paragraph();
paragraph2.Add("LINE 2");
paragraph2.Font = font;
pdfDoc.Add(paragraph2);
// Does use font
var paragraph3 = new Paragraph();
paragraph3.Font = font;
paragraph3.Add("LINE 3"); // This must be done after setting the font
pdfDoc.Add(paragraph3);
var cb = writer.DirectContent;
pdfDoc.Close();
}
}
I discovered that you need to set the font first before you write the text. The following code outputs the PDF with the following properties. I didn't get the TrueType requirement out of this, but perhaps this will set you in the right direction.
Where I'm using paragraph and paragraph2 will use the default font which was Helvetica for me because I'm setting the font after I'm setting the text. Order does matter!
The documentation for this certainly needs to be expanded upon...
I need to remove the first few pages of a PDF file. Apparently, the easiest way to do that is to create a copy of it and not duplicate the unwanted pages. This works, but they look a lot smaller than they should. Any ideas?
How it should look
How it actually looks
private static void ClipSpecificPDF(string input, string output, int pagesToCut)
{
PdfReader myReader = new PdfReader(input);
using (FileStream fs = new FileStream(output, FileMode.Create, FileAccess.Write, FileShare.None))
{
using (Document doc = new Document())
{
using (PdfWriter myWriter = PdfWriter.GetInstance(doc, fs))
{
//Open the desitination for writing
doc.Open();
//Loop through each page that we want to keep
for (int i = pagesToCut; i < myReader.NumberOfPages; i++)
{
//Add a new blank page to destination document
var PS = myReader.GetPageSizeWithRotation(i);
myWriter.SetPageSize(PS);
doc.NewPage();
//Extract the given page from our reader and add it directly to the destination PDF
myWriter.DirectContent.AddTemplate(myWriter.GetImportedPage(myReader, i + 1), 0, 0);
}
//Close our document
doc.Close();
}
}
}
}
The problem you describe is explained in the FAQ. For instance in the answer to the questions:
How to merge documents correctly?
Why does the function to concatenate / merge PDFs cause issues in some cases?
Using PdfWriter to manipulate PDF documents is a very bad idea. Read chapter 6 of my book to discover why this is a bad idea, and take a look at Table 6.1 to find out which class is a better fit.
In the same chapter, you'll find the SelectPages example. Suppose that you want to create a new PDF containing only page 4 to 8. In that case, you simply use the SelectPages() method and PdfStamper:
PdfReader reader = new PdfReader(src);
reader.SelectPages("4-8");
PdfStamper stamper = new PdfStamper(reader, new FileStream(dest, FileMode.Create, FileAccess.Write));
stamper.Close();
reader.Close();
By using PdfReader, the page size is preserved, as well as any of the interactive features that may be present.
Your approach is bad because you do not respect the original page size: you copy a document with letter (?) format to a document with A4 pages. If the origin of the page doesn't correspond with the lower-left corner, parts of your document will be invisible. If there are interactive features in your PDF, they will be lost. Of all the possible examples you could have followed, you picked the worst one...
I have PDF template file with fields.
Template created by customer. It has some text, field labels and fields itself. Text and labels uses some font which is embedded within the template.
Problems occur when I try to fill fields with cyrillic values - there is no cyrillic symbols in result document.
I saw a lot of similar problems which were solved by using substitution font for AcroFields. But here I can't use one specific font for substitution, because I can't define field font in template.
I tried to set different fonts for fields in Acrobat Editor - Times New Roman, Arial and other well known Windows fonts, but there is no effect in resulting pdf.
Code sample:
FontFactory.RegisterDirectory(Environment.GetFolderPath(Environment.SpecialFolder.Fonts));
using (var dest = File.Create(#"result.pdf"))
{
using (var stamper = new PdfStamper(reader, dest))
{
var fields = stamper.AcroFields;
fields.SetField("ClientName", "Имя клиента");
stamper.FormFlattening = true;
stamper.Close();
}
}
I even registered all available fonts in FontFactory, but there was no effect.
So the questions are:
1. If I can embed font in Adobe Acrobat used for fields only, then how to do it?
2. If I can define font family for existing field with iTextSharp, then how to do it?
Well, I wrote solution suitable for me.
Register all existing system fonts in FontFactory.
Read document metadata to extract all used fonts in documents.
Read fields metadata and try to create BaseFont suitable to field font. If there is no suitable font - use fallback font (arial with encoding IDENTITY_H).
So full code looks like:
static IEnumerable<PdfFontInfo> ReadDocumentFonts(PdfReader reader)
{
if (reader.AcroForm == null)
yield break;
var dr = reader.AcroForm.GetAsDict(PdfName.DR);
// Read font information from resources
var fontDict = dr.GetAsDict(PdfName.FONT);
foreach (var fontKey in fontDict.Keys)
{
var data = fontDict.GetAsDict(fontKey);
// Read font descriptor if it possible
var descriptor = data.GetAsDict(PdfName.FONTDESCRIPTOR);
if (descriptor != null)
{
// Read font name and family
var family = descriptor.GetAsString(PdfName.FONTFAMILY);
yield return new PdfFontInfo(fontKey, family.ToUnicodeString());
}
}
}
static IReadOnlyList<BaseFont> CreateSubstitutionFontsForFields(PdfReader reader)
{
if (reader.AcroForm.Fields == null)
return new List<BaseFont>(0);
var documentFontMap = ReadDocumentFonts(reader).ToDictionary(f => f.Name, StringComparer.InvariantCultureIgnoreCase);
var substFonts = new Dictionary<string, BaseFont>();
var fallbackRequired = false;
// Read font information of each field
foreach (var field in reader.AcroForm.Fields)
{
var fieldFontDa = field.Info.GetAsString(PdfName.DA);
if (fieldFontDa == null)
continue;
var parts = AcroFields.SplitDAelements(fieldFontDa.ToUnicodeString());
if (parts.Length == 0)
continue;
var fontName = (string) parts[0];
PdfFontInfo inf;
if (documentFontMap.TryGetValue(fontName, out inf))
{
if (!substFonts.ContainsKey(fontName))
{
var font = FontFactory.GetFont(fontName, BaseFont.IDENTITY_H, true).BaseFont;
substFonts.Add(fontName, font);
}
}
else
fallbackRequired = true;
}
var allFonts = new List<BaseFont>(substFonts.Values);
if (fallbackRequired)
allFonts.Add(FALLBACK_FONT);
return allFonts;
}
If you can find any errors, you are welcome to comment.
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();