How to replace MultiColumnText with ColumnText in iText - c#

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

Related

Create borderless table in iText 7

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.

How to efficiently generate a table with a large number of rows using iText 7

I am trying to generate a PDF document using iText 7 core library. The problem I currently have is that it is really slow and for the number of entries I have tested with (3000 rows where one row is composed of 12 columns. The actual needed number later will be much higher) takes around 3 minutes.
Below I give you what I have already tried and the methods that actually give me the slow writing results.
await Task.Run(() =>
{
LoadLicense();
listOfValues = GetListOfValues(values);
var pdfDocument = new PdfDocument(new PdfWriter(targetPath));
var document = new Document(pdfDocument, PageSize.A4);
var table = new Table(new[] { 10f, 5f, 5f, 5f, 5f, 5f, 5f, 5f, 5f, 5f, 5f, 5f });
table.SetWidth(UnitValue.CreatePercentValue(100))
.SetTextAlignment(TextAlignment.CENTER)
.SetHorizontalAlignment(HorizontalAlignment.CENTER);
// HeaderTitlesList is just an array of strings
foreach (var title in HeaderTitlesList)
{
WriteHeader(table, title);
}
for (var row = 0; row < measurement.MeasurementPoints.Count; row++)
{
WriteRow(table, $"{listOfValues[row].main}");
WriteRow(table, $"{listOfValues[row].first}");
WriteRow(table, $"{listOfValues[row].second}");
WriteRow(table, $"{listOfValues[row].third}");
WriteRow(table, $"{listOfValues[row].fifth:0.###}");
WriteRow(table, $"{listOfValues[row].sixth}");
WriteRow(table, $"{listOfValues[row].seventh:0.###}");
WriteRow(table, $"{listOfValues[row].eighth}");
WriteRow(table, $"{listOfValues[row].nineth}");
WriteRow(table, $"{listOfValues[row].tenth:0.###}");
WriteRow(table, $"{listOfValues[row].main:0}");
WriteRow(table, $"{listOfValues[row].main:0.##}");
}
document.Add(table);
document.Close();
}, cancellationToken);
return true;
}
private static void WriteRow(Table table, string cellVal)
{
table.AddCell(cellVal).SetBorder(new SolidBorder(new DeviceRgb(0, 0, 0), 0.5f));
}
private static void WriteHeader(Table table, string title)
{
var cell = new Cell().Add(new Paragraph(title));
cell.SetFont(PdfFont)
.SetBackgroundColor(new DeviceRgb(0, 74, 136))
.SetFontColor(new DeviceRgb(255, 255, 255))
.SetPadding(5)
.SetBorder(CellBorder);
table.AddHeaderCell(cell);
}
Is there a way to perhaps instead of writing all these values cell by cell generate them row by row? Anything that would make the PDF generating process at least a tad quicker is appreciated.
EDIT:
I have just tried to use the iText suggested method from a post here and tried a rather small, in our case, use case where around 40 000 cells had to be written. This already takes over a minute.
protected void manipulatePdf(string dest)
{
var pdfDoc = new PdfDocument(new PdfWriter(dest));
var doc = new Document(pdfDoc);
var table = new Table(UnitValue.CreatePercentArray(12), true);
foreach (var cellVal in HeaderTitlesList)
{
table.AddHeaderCell(new Cell().SetKeepTogether(true).Add(new Paragraph(cellVal)));
}
doc.Add(table);
for (int i = 0; i < 40000; i++)
{
if (i % 12 == 0)
{
table.Flush();
}
table.AddCell(new Cell().SetKeepTogether(true).Add(new Paragraph("Test " + i).SetMargins(0, 0, 0, 0)));
}
table.Complete();
doc.Close();
}
This leads me to think that this library is just not "quick" enough for our use case.

Xceed Docx Wrong paragraph spacing in table cells

I am using the Xceed Docx library to generate a Word document which contains a lot of tables with the following formatting
Expected
The problem is that the library seems to insert a spacing before the cells' first paragraph, which renders as follows
Actual rendering
Here's the code I use to generate the table
private Table InitTable(DocX document)
{
int rows = Util.ListNullOrEmpty(reponses) ? 3 : 2 + reponses.Count;
int columns = 6;
var table = document.AddTable(rows, columns);
table.Rows[0].MergeCells(4, 5);
table.Rows[0].Cells[0].Width = 34; // 12 mm
table.Rows[0].Cells[1].Width = 127.55; // 45 mm
table.Rows[0].Cells[2].Width = 104.88; // 37 mm
table.Rows[0].Cells[3].Width = 104.88; // 37 mm
table.Rows[0].Cells[4].Width = 104.88; // 37 mm
Border border = new Border(BorderStyle.Tcbs_thick, BorderSize.one, 10, System.Drawing.Color.Black);
List<string> enteteLigne1 = new List<string>
{
"Column 1", "Column 2", "Column 3", "Column 4", "Column 5"
};
// Header : First row
for (int i = 0; i < columns -1; i++)
{
SetCellBorder(table.Rows[0].Cells[i], border, 0b0000);
FormatCellContent(table.Rows[0].Cells[i], enteteLigne1[i], "Arial", 10d, Alignment.center);
}
return table;
}
private void FormatCellContent(Cell cell, string content, string fontName, double fontSize, Alignment alignment)
{
var p = cell.Paragraphs.FirstOrDefault();
if (p == null)
{
p = cell.InsertParagraph();
}
p.SpacingBefore(2.9); // 1 mm * 2.834645669 * 20 (OpenXML unit)
p.SpacingAfter(2.9);
p.Alignment = alignment;
p.Font(fontName);
p.FontSize(fontSize);
p.InsertText(content);
}
The only alternative is to insert OpenXml code into the paragraph's Xml property, but that would be tedious and somehow defies the purpose of using the library.
What did I do wrong ?
Thanks in advance
Instead of
table.Rows[0].Cells[0].Width = 34;
use
table.SetColumnWidth(0, 34);
which will define the column width of the table

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

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