Create borderless table in iText 7 - c#

I am porting an application from iTextSharp 5 to iText 7. In the original application I added page numbers using a stamper that added a table to the top of the page. I have almost succeeded but I am unable to create a table with only a bottom border (internal, left, right and top is borderless. I tried the example from the iText building blocks book and have looked at itext 7 table borderless
But I still get top, internal and side borders. Here is my code:
private Table makepagetable(string doctitle, int curpage, int totalpage)
{
PdfFont font = PdfFontFactory.CreateFont(iText.IO.Font.Constants.StandardFonts.TIMES_ROMAN);
Text title = new Text(doctitle).SetFontSize(11f).SetFont(font);
Text pages = new Text("page " + curpage.ToString() + " of " + totalpage.ToString()).SetFont(font);
Paragraph p1 = new Paragraph(title).SetTextAlignment(TextAlignment.LEFT);
Paragraph p2 = new Paragraph(pages).SetTextAlignment(TextAlignment.RIGHT);
Table mytable = new Table(new float[] { 3, 1 })
.SetBorderTop(Border.NO_BORDER)
.SetBorderRight(Border.NO_BORDER)
.SetBorderLeft(Border.NO_BORDER)
.SetBorderBottom(new SolidBorder(2));
float pval = 500;
mytable.SetWidth(pval);
mytable.AddCell(new Cell().Add(p1)).SetBorder(Border.NO_BORDER);
mytable.AddCell(new Cell().Add(p2)).SetBorder(Border.NO_BORDER);
// SetBorderTop(Border.NO_BORDER).SetBorderLeft(Border.NO_BORDER).SetBorderRight(Border.NO_BORDER);
return mytable;
}
I have also tried mytable.AddCell(new Cell().Add(p2)).SetBorderTop(Border.NO_BORDER).SetBorderLeft(Border.NO_BORDER).SetBorderRight(Border.NO_BORDER); and various similar combinations on the table object, but I still get the borders.
For completion here is the routine that calls this function
public Byte[] AddPageNumbers(Byte[] firstpass, string doctitle) {
//firstpass = array of the original pdfdocument
// doctitle = text on left of table
int i;
float x = 30;
float y = 810;
MemoryStream ms2 = new MemoryStream(firstpass);
PdfReader reader = new PdfReader(ms2);
MemoryStream ms3 = new MemoryStream();
PdfDocument pdfDoc = new PdfDocument(reader, new PdfWriter(ms3));
Document document = new Document(pdfDoc, PageSize.A4, false);
int n = pdfDoc.GetNumberOfPages();
for (i = 3; i <= n; i++)
{
Paragraph header;
//PdfPage page = pdfDoc.GetPage(i);
//header = new Paragraph(String.Format(doctitle + " Page {0} of {1}", i, n));
Table table;
PdfPage page = pdfDoc.GetPage(i);
table = makepagetable(doctitle, i, n);
header = new Paragraph().Add(table);
document.ShowTextAligned(header,x,y, i, TextAlignment.JUSTIFIED, VerticalAlignment.MIDDLE, 0);
}
document.Close();
pdfDoc.Close();
return ms3.ToArray();
}

Borderless Table or Cell, for c# and iText7, you can use:
//Table with no border
table.SetBorder(Border.NO_BORDER);
//Cell with no border
cell.SetBorder(Border.NO_BORDER);
I review your code:
//your source code
mytable.AddCell(new Cell().Add(p1)).SetBorder(Border.NO_BORDER);
//changed code
mytable.AddCell(new Cell().Add(p1).SetBorder(Border.NO_BORDER));
Hope this is helpful.

Related

Create indents and numeration in Table of Content(itextsharp)

I have a question about TOC. How can I create TOC With indents and numeration?
Now I have TOC without it(just list). I create it using Chunk and Paragraph. What should I use for creating TOC with it? Maybe should I use List and add to document or not?
Here I'm creating TOC:
private int CreateTOC(XmlNode xmlNode, Document doc, PdfWriter writer, int number)
{
var toc = ev.GetTOC();
KeyValuePair<string, int> value;
Chunk dottedLine = new Chunk(new iTextSharp.text.pdf.draw.DottedLineSeparator());
for (int i = 0; i < xmlNode.ChildNodes.Count; i++)
{
var text = xmlNode.ChildNodes[i].Attributes["text"].Value;
value = toc[text];
var dest = value.Key;
var page = value.Value;
var c = new Chunk((i+1).ToString()+ ". " + text, font);
c.SetAction(PdfAction.GotoLocalPage(dest, false));
var p = new Paragraph(c);
p.Add(dottedLine);
c = new Chunk(page.ToString(), font);
c.SetAction(PdfAction.GotoLocalPage(dest, false));
p.Add(c);
doc.Add(p);
CreateTOC(xmlNode.ChildNodes[i], doc, writer, i+1);
}
return writer.PageNumber;
}
And I get list with reference to chapters in content.
But I need the following:
1. chapter1-------------------1page
1.1 subchupter1-------------2page
1.2 subchupter2-------------2page
1.3 subchupter3-------------3page
2. chupter2-------------------4page
2.1 subchupter4-------------4page
2.3 subchupter4-------------4page
2.3.1 subsubchupter------5page
...
...
...
How can I fix it?
Thank you!
Introduce a level and multiply that level with an indentation value. Use that value as the value for IndentationLeft:
private int CreateTOC(XmlNode xmlNode, Document doc, PdfWriter writer, int number, int level) {
var toc = ev.GetTOC();
KeyValuePair<string, int> value;
Chunk dottedLine = new Chunk(new iTextSharp.text.pdf.draw.DottedLineSeparator());
for (int i = 0; i < xmlNode.ChildNodes.Count; i++)
{
var text = xmlNode.ChildNodes[i].Attributes["text"].Value;
value = toc[text];
var dest = value.Key;
var page = value.Value;
var c = new Chunk((i+1).ToString()+ ". " + text, font);
c.SetAction(PdfAction.GotoLocalPage(dest, false));
var p = new Paragraph(c);
p.IndentationLeft = 10 * level;
p.Add(dottedLine);
c = new Chunk(page.ToString(), font);
c.SetAction(PdfAction.GotoLocalPage(dest, false));
p.Add(c);
doc.Add(p);
CreateTOC(xmlNode.ChildNodes[i], doc, writer, i+1, level + 1);
}
return writer.PageNumber;
}
Use 0 for the level when you first call CreateToc().

ABCpdf, render an HTML within a "template": How to add margin?

I'm trying to render an HTML within a predefined PDF-template (e.g. within a frame.) The template/frame should reach the edges. But the HTML shouldn't do that. So I need some kind of margin for the HTML only. Here is my code so far:
var doc = new Doc();
doc.MediaBox.String = "A4";
doc.Rect.String = doc.MediaBox.String;
var id = doc.AddImageUrl(url.ToString());
doc.AddImageDoc("template.pdf", 1, doc.MediaBox);
while (doc.Chainable(id))
{
doc.Page = doc.AddPage();
id = doc.AddImageToChain(id);
doc.AddImageDoc("template.pdf", 1, doc.MediaBox);
}
for (var i = 1; i <= doc.PageCount; i++)
{
doc.PageNumber = i;
doc.Flatten();
}
I see, that there is a possibility to pass a Rect to #AddImageDoc. But I don't have this option for #AddImageUrl.
Here is how I could solve the problem:
First, I set the position and margins of the doc.Rect:
doc.Rect.Position(15, 15);
doc.Rect.Width = pageWidth - 2*15;
doc.Rect.Height = pageHeight - 2*15;
Then I filled the doc with the images from the parsed URL:
var id = doc.AddImageUrl(url.ToString());
while (doc.Chainable(id))
{
doc.Page = doc.AddPage();
id = doc.AddImageToChain(id);
}
After this, I reset the doc.Rect to the size of the actual paper (in ma case: A4):
doc.Rect.String = "A4";
Now I can loop over all pages and add the template to them:
for (var i = 1; i <= doc.PageCount; i++)
{
doc.PageNumber = i;
doc.AddImageDoc(template, 1, doc.Rect);
doc.Flatten();
}

Read columns of PDF in C# using ItextSharp

In my progam I extracted text from a PDF file and it works well. ItextSharp extracts text from PDF line by line. However, when a PDF file contains 2 columns, the extracted text is not ok as in each line joins two columns.
My problem is: How can I extract text column by column?
Below is my code. PDF files are Arabic. I'm sorry my English is not so good.
PdfReader reader = new PdfReader(#"D:\test pdf\Blood Journal.pdf");
int intPageNum = reader.NumberOfPages;
string[] words;
string line;
for (int i = 1; i <= intPageNum; i++)
{
text = PdfTextExtractor.GetTextFromPage(reader, i,
new LocationTextExtractionStrategy());
words = text.Split('\n');
for (int j = 0, len = words.Length; j < len; j++)
{
line = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(words[j]));
// other things here
}
// other things here
}
You may want to use RegionTextRenderFilter to restrict a column region then use LocationTextExtractionStrategy to extract the text. However this requires prior knowledge to the PDF file your are parsing, i.e. you need information about the column's position and size.
In more details, you need to pass in the coordinates of your column to define a rectangle, then extract the text from that rectangle. A sample will be like this:
PdfReader reader = new PdfReader(#"D:\test pdf\Blood Journal.pdf");
int intPageNum = reader.NumberOfPages;
private string GetColumnText(float llx, float lly, float urx, float ury)
{
// reminder, parameters are in points, and 1 in = 2.54 cm = 72 points
var rect = new iTextSharp.text.Rectangle(llx, lly, urx, ury);
var renderFilter = new RenderFilter[1];
renderFilter[0] = new RegionTextRenderFilter(rect);
var textExtractionStrategy =
new FilteredTextRenderListener(new LocationTextExtractionStrategy(),
renderFilter);
var text = PdfTextExtractor.GetTextFromPage(reader, intPageNum,
textExtractionStrategy);
return text;
}
Here is another post discussing what you want, you may want to check as well: iTextSharp - Reading PDF with 2 columns. But they didn't hit the solution either :(

How to replace MultiColumnText with ColumnText in iText

I have such statements in the code
MultiColumnText mct = new MultiColumnText(MultiColumnText.AUTOMATIC);
mct.AddRegularColumns(document.Left, document.Right, 30f, 2);
mct.AddElement(table);
But after upgrade iText to 5.3.3 they have removed MultiColumnText and suggest use ColumnText instead!
What way to rewrite this code with ColumnText
There are plenty of examples available. Look for the keyword ColumnText.
See for instance this example: http://itextpdf.com/examples/iia.php?id=68
The code you need looks like this:
float middle = (document.left() + document.right()) / 2;
float[][] columns = {
{ document.left(), document.bottom(), middle - 15, document.top() } ,
{ middle + 15, document.bottom(), document.right(), document.top() }
};
ColumnText ct = new ColumnText(writer.getDirectContent());
ct.addElement(table);
int column = 0;
int status = ColumnText.START_COLUMN;
while (ColumnText.hasMoreText(status)) {
ct.setSimpleColumn(
COLUMNS[column][0], columns[column][1],
COLUMNS[column][2], columns[column][3]);
status = column.go();
if (++count > 1) {
count = 0;
document.newPage();
}
}

With iTextSharp, how to rightalign a container of text (but keeping the individual lines leftaligned)

I don't know the width of the texts in the textblock beforehand, and I want the the textblock to be aligned to the right like this, while still having the individual lines left-aligned:
Mr. Petersen |
Elmstreet 9 |
888 Fantastic City|
(| donotes the right edge of the document)
It should be simple, but I can't figure it out.
I've tried to put all the text in a paragraph and set paragraph.Alignment = Element.ALIGN_RIGHT, but this will rightalign the individual lines.
I've tried to put the paragraph in a cell inside a table, and rightalign the cell, but the cell just takes the full width of the table.
If I could just create a container that would take only the needed width, I could simply rightalign this container, so maybe that is really my question.
Just set the Paragraph.Align property:
using (Document document = new Document()) {
PdfWriter.GetInstance(
document, STREAM
);
document.Open();
for (int i = 1; i < 11; ++i) {
Paragraph p = new Paragraph(string.Format(
"Paragraph {0}", i
));
p.Alignment = Element.ALIGN_RIGHT;
document.Add(p);
}
}
It even works with a long string like this:
string longString = #"
iText ® is a library that allows you to create and manipulate PDF documents. It enables developers looking to enhance web- and other applications with dynamic PDF document generation and/or manipulation.
";
Paragraph pLong = new Paragraph(longString);
pLong.Alignment = Element.ALIGN_RIGHT;
document.Add(pLong);
EDIT:
After looking at the "picture" you drew...
It doesn't match with the title. The only way you can align individual Paragraph objects like your picture is if the "paragraph" does NOT exceed the Document object's "content" box (for a lack of a better term). In other words, you won't be able to get that type of alignment if the amount of text exceeds that which will fit on a single line.
With that said, if you want that type of alignment you need to:
Calculate the widest value from the collection of strings you intend to use.
Use that value to set a common left indentation value for the Paragraphs.
Something like this:
using (Document document = new Document()) {
PdfWriter.GetInstance(
document, STREAM
);
document.Open();
List<Chunk> chunks = new List<Chunk>();
float widest = 0f;
for (int i = 1; i < 5; ++i) {
Chunk c = new Chunk(string.Format(
"Paragraph {0}", Math.Pow(i, 24)
));
float w = c.GetWidthPoint();
if (w > widest) widest = w;
chunks.Add(c);
}
float indentation = document.PageSize.Width
- document.RightMargin
- document.LeftMargin
- widest
;
foreach (Chunk c in chunks) {
Paragraph p = new Paragraph(c);
p.IndentationLeft = indentation;
document.Add(p);
}
}
UPDATE 2:
After reading your updated question, here's another option that lets you add text to the left side of the "container":
string textBlock = #"
Mr. Petersen
Elmstreet 9
888 Fantastic City
".Trim();
// get the longest line to calcuate the container width
var widest = textBlock.Split(
new string[] {Environment.NewLine}
, StringSplitOptions.None
)
.Aggregate(
"", (x, y) => x.Length > y.Length ? x : y
)
;
// throw-away Chunk; used to set the width of the PdfPCell containing
// the aligned text block
float w = new Chunk(widest).GetWidthPoint();
PdfPTable t = new PdfPTable(2);
float pageWidth = document.PageSize.Width
- document.LeftMargin
- document.RightMargin
;
t.SetTotalWidth(new float[]{ pageWidth - w, w });
t.LockedWidth = true;
t.DefaultCell.Padding = 0;
// you can add text in the left PdfPCell if needed
t.AddCell("");
t.AddCell(textBlock);
document.Add(t);

Categories

Resources