Absolute position for html to pdf itextsharp - itext

Hi I was trying to convert html to pdf using below code . It seems like if my html content has a absolute position then the parser is ignoring it.
This is a sample html i tried to convert
STATE OF MARYLAND
var cssText = string.Empty;
var htmlText = string.Empty;
htmlText = _busrenew.GetLicenseTemplate("LicenseTemplate");
var memoryStream = new MemoryStream();
var document = new Document(PageSize.A4);
var writer = PdfWriter.GetInstance(document, memoryStream);
document.Open();
using (var cssMemoryStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(cssText)))
{
using (var htmlMemoryStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(htmlText)))
{
XMLWorkerHelper.GetInstance().ParseXHtml(writer, document, htmlMemoryStream, cssMemoryStream);
}
}
document.Close();
var pdfContent = new PdfContent
{
MemoryStream = memoryStream,
FileName = "SomeName"
};

Its not supported use position relative
When using position relative the only other change you will need to make to accommodate this is changing the pixels for the top

The following solution worked for me in the iText HtmlToPdf. Place this between style block.
#img_test {
position: absolute;
top: 2px;
left: 0px;
z-index: -1;
}

Related

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.

How do I change the weight of a simulated bold font using itext

I am using the iText library to generate text. I am loading the Arial Unicode MS font which does not contain a bold style so iText is simulating the bold. This works fine, but the weight of the bold font appears too heavy compared with text generated using the Java API or even using Microsoft Word.
I tried to get the weight from the FontDescriptor, but the value returned is always 0.0
float weight = font.getBaseFont().getFontDescriptor(BaseFont.FONT_WEIGHT, fontSize);
Is there a way I can change the weight of a simulated bold font?
As an addendum to #Chris' answer: You do not need to construct those Object[]s as there is a Chunk convenience method:
BaseFont arialUnicodeMs = BaseFont.createFont("c:\\Windows\\Fonts\\ARIALUNI.TTF", BaseFont.WINANSI, BaseFont.EMBEDDED);
Font arial12 = new Font(arialUnicodeMs, 12);
Paragraph p = new Paragraph();
for (int i = 1; i < 100; i++)
{
Chunk chunk = new Chunk(String.valueOf(i) + " ", arial12);
chunk.setTextRenderMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE, i/100f, null);
p.add(chunk);
}
document.add(p);
results in
EDIT
Sorry, I just realized after posting this that you're using iText but my answer is for iTextSharp. You should, however, be able to use most of the code below. I've updated the source code link to reference the appropriate Java source.
Bold simulation (faux bold) is done by drawing the text with a stroke. When iText is asked to draw bold text with a non-bold font it defaults to applying a stroke with a width of of the font's size divided by 30. You can see this in the current source code here. The magic part is setting the chunk's text rendering mode to a stroke of your choice:
//.Net code
myChunk.Attributes[Chunk.TEXTRENDERMODE] = new Object[] { PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE, MAGIC_NUMBER_HERE, null };
//Java code
myChunk.attributes.put(Chunk.TEXTRENDERMODE, new Object[]{Integer.valueOf(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE), MAGIC_NUMBER_HERE, null});
Knowing that you can just apply the same logic but using your weight preference. The sample below creates four chunks, the first normal, the second faux-bold, the third ultra-heavy faux-bold and the fourth ultra-lite faux-bold.
//.Net code below but should be fairly easy to convert to Java
//Path to our PDF
var testFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.pdf");
//Path to our font
var ff = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "ARIALUNI.TTF");
//Normal document setup, nothing special here
using (var fs = new FileStream(testFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (var doc = new Document()) {
using (var writer = PdfWriter.GetInstance(doc, fs)) {
doc.Open();
//Register our font
FontFactory.Register(ff, "Arial Unicode MS");
//Declare a size to use throughout the demo
var size = 20;
//Get a normal and a faux-bold version of the font
var f = FontFactory.GetFont("Arial Unicode MS", BaseFont.IDENTITY_H, BaseFont.EMBEDDED, size, iTextSharp.text.Font.NORMAL);
var fb = FontFactory.GetFont("Arial Unicode MS", BaseFont.IDENTITY_H, BaseFont.EMBEDDED, size, iTextSharp.text.Font.BOLD);
//Create a normal chunk
var cNormal = new Chunk("Hello ", f);
//Create a faux-bold chunk
var cFauxBold = new Chunk("Hello ", fb);
//Create an ultra heavy faux-bold
var cHeavy = new Chunk("Hello ", f);
cHeavy.Attributes = new Dictionary<string, object>();
cHeavy.Attributes[Chunk.TEXTRENDERMODE] = new Object[] { PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE, size / 10f, null };
//Create a lite faux-bold
var cLite = new Chunk("Hello ", f);
cLite.Attributes = new Dictionary<string, object>();
cLite.Attributes[Chunk.TEXTRENDERMODE] = new Object[] { PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE, size / 50f, null };
//Add to document
var p = new Paragraph();
p.Add(cNormal);
p.Add(cFauxBold);
p.Add(cHeavy);
p.Add(cLite);
doc.Add(p);
doc.Close();
}
}
}

itextSharp - html to pdf some turkish characters are missing

When I am trying to generate PDF from HTML, some Turkish characters like ĞÜŞİÖÇ ğüşıöç are missing in PDF, I see a space in place of these characters but i want to print that character.
My code is:
public virtual void print pdf(string html, int id)
{
String htmlText = html.ToString();
Document document = new Document();
string filePath = HostingEnvironment.MapPath("~/Content/Pdf/");
PdfWriter.GetInstance(document, new FileStream(filePath + "\\pdf-"+id+".pdf", FileMode.Create));
document.Open();
iTextSharp.text.html.simpleparser.HTMLWorker hw =
new iTextSharp.text.html.simpleparser.HTMLWorker(document);
hw.Parse(new StringReader(htmlText));
document.Close();
}
How to print all Turkish characters on PDF?
I have finally find a solution for this problem, by this you can print all Turkish character.
String htmlText = html.ToString();
Document document = new Document();
string filePath = HostingEnvironment.MapPath("~/Content/Pdf/");
PdfWriter.GetInstance(document, new FileStream(filePath + "\\pdf-"+Name+".pdf", FileMode.Create));
document.Open();
iTextSharp.text.html.simpleparser.HTMLWorker hw = new iTextSharp.text.html.simpleparser.HTMLWorker(document);
FontFactory.Register(Path.Combine(_webHelper.MapPath("~/App_Data/Pdf/arial.ttf")), "Garamond"); // just give a path of arial.ttf
StyleSheet css = new StyleSheet();
css.LoadTagStyle("body", "face", "Garamond");
css.LoadTagStyle("body", "encoding", "Identity-H");
css.LoadTagStyle("body", "size", "12pt");
hw.SetStyleSheet(css);
hw.Parse(new StringReader(htmlText));
Same my problem solved this code;
var pathUpload = Server.MapPath($"~/Test.pdf");
using (var fs = System.IO.File.Create(pathUpload))
{
using (var doc = new Document(PageSize.A4, 0f, 0f, 10f, 10f))
{
using (var writer = PdfWriter.GetInstance(doc, fs))
{
doc.Open();
BaseFont baseFont = BaseFont.CreateFont("C:\\Windows\\Fonts\\Arial.ttf", "windows-1254", true);
Font fontNormal = new Font(baseFont, 24, Font.NORMAL);
var p = new Paragraph("Test paragrapgh İÇşıĞğŞçöÖ", fontNormal);
doc.Add(p);
doc.Close();
}
} }
I had the same prolem after a few days of reserach;
BaseFont myFont = BaseFont.CreateFont(#"C:\windows\fonts\arial.ttf", "windows-1254", BaseFont.EMBEDDED);
Font fontNormal = new Font(myFont);
Eveytime you need to write a text having special characters, do it this way;
doc.Add(new Paragraph("İıĞğŞşÜüÖöŞşÇç", fontNormal)); // a new paragraph
results.Add(new ListItem("İıĞğŞşÜüÖöŞşÇç", fontNormal)); // a new list item
additionally, this may be needed for itextsharp to let font change;
using Font = iTextSharp.text.Font;
it works like a charm :)
I had a similar problem and I couldn't get the CP1254 encoding to work but I found another solution which worked for me.
In the css just add "font-family: Arial;" and put it on the outer div tag.
.className{
font-family: Arial;
}
<div class="className">
...
</div>
I found this answer here: How to generate a valid PDF/A file using iText and XMLWorker (HTML to PDF/A process)
It took a long time to find this solution but I found it searching for a font solution to display Turkish characters.

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.