Reputation: 2035
I want to draw a schedule, based on a table (including borders), where some of the cells are (partly) filled with a color. This color is based on PdfTemplate which is added as an image to the cell.
I've create a test project for it, and attached placed the output at: PDF output
In the example, I expect it to draw the filled line, everytime 2 blocks larger. As you can see, it is a bit more than the 2 blocks.
The template I create, should be the exact the size of the table cells. So I don't understand, why it keeps getting bigger every iteration.
Any ideas how to fix this?
public Test()
{
int cellWidth = 23;
int usernameCellWith = 86;
float[] scheduleTableColumnWidths = new float[33];
scheduleTableColumnWidths[0] = usernameCellWith;
for (int i = 1; i <= 32; i++)
scheduleTableColumnWidths[i] = cellWidth;
using (MemoryStream stream = new MemoryStream())
{
Rectangle rect = PageSize.GetRectangle("A4");
rect = new Rectangle(rect.Height, rect.Width, 90);
using (Document document = new Document(rect, 10f, 10f, 10f, 10f))
{
PdfWriter writer = PdfWriter.GetInstance(document, stream);
if (!document.IsOpen())
{
document.NewPage();
document.Open();
}
PdfPTable containerTable = new PdfPTable(1);
containerTable.DefaultCell.Border = Rectangle.NO_BORDER;
containerTable.WidthPercentage = 100;
PdfPTable scheduleTable = new PdfPTable(scheduleTableColumnWidths);
for (int iRow = 0; iRow <= 23; iRow++)
{
PdfPCell usernameCell = new PdfPCell(new Phrase("user "+ iRow));
usernameCell.FixedHeight = cellWidth;
scheduleTable.AddCell(usernameCell);
for (int iColumn = 1; iColumn <= 32; iColumn++)
{
PdfPCell cell = new PdfPCell();
cell.FixedHeight = cellWidth;
if (iColumn == 1 && iRow % 2 == 0)
{
float width = (float)(iRow + 1) * cellWidth;
PdfTemplate template = writer.DirectContent.CreateTemplate(width, cellWidth);
template.SetColorFill(new BaseColor(System.Drawing.ColorTranslator.FromHtml("#255C8A")));
template.Rectangle(0, 0, width, cellWidth);
template.Fill();
cell = new PdfPCell(Image.GetInstance(template));
}
scheduleTable.AddCell(cell);
}
scheduleTable.CompleteRow();
}
containerTable.AddCell(scheduleTable);
containerTable.CompleteRow();
document.Add(containerTable);
document.CloseDocument();
}
}
}
Upvotes: 1
Views: 2106
Reputation: 55457
Do you absolutely need to use a PdfTemplate
? Unless you've just posted a simplified version of your code it is screaming to use a colspan
instead and then iText will just calculate everything for you.
Below is a modified version of what you posted. I moved some of your "magic numbers" to variables just to help my own mental process. They might not be named ideally but they do the job. Also, when working in a double for
loop I recommend always looping over rows and columns and then performing logic. Your code loops over rows, does some logic for a "first cell" and then loops over a subset of the columns and performs more logic. Although absolutely 100% valid I personally find it confusing, especially when having to jump between 1 and 0 as a starting value.
Also, also, I very strongly recommend avoiding CompleteRow()
. It exists to solve a certain problem but it also literally means "my logic above might be wrong so iText, could you just fudge the numbers for me?"
I commented most of what I changed so hopefully this is helpful.
public void Test() {
int cellWidth = 23;
int usernameCellWith = 86;
int maxNumberOfColumns = 32;
int maxNumberOfRows = 24;
float[] scheduleTableColumnWidths = new float[maxNumberOfColumns];
scheduleTableColumnWidths[0] = usernameCellWith;
for (int i = 1; i < maxNumberOfColumns; i++)
scheduleTableColumnWidths[i] = cellWidth;
using (MemoryStream stream = new MemoryStream()) {
iTextSharp.text.Rectangle rect = PageSize.GetRectangle("A4");
rect = new iTextSharp.text.Rectangle(rect.Height, rect.Width, 90);
using (Document document = new Document(rect, 10f, 10f, 10f, 10f)) {
PdfWriter writer = PdfWriter.GetInstance(document, stream);
//Unless this code is just a sample, a new document is never open and NewPage() is implied so these four lines could just be document.Open();
if (!document.IsOpen()) {
document.NewPage();
document.Open();
}
PdfPTable containerTable = new PdfPTable(1);
containerTable.DefaultCell.Border = iTextSharp.text.Rectangle.NO_BORDER;
containerTable.WidthPercentage = 100;
PdfPTable scheduleTable = new PdfPTable(scheduleTableColumnWidths);
//Loop through each row
for (int iRow = 0; iRow < maxNumberOfRows; iRow++) {
//Loop through each column
for (int iColumn = 0; iColumn < maxNumberOfColumns; iColumn++) {
//Placeholder variable that will be instantiated within the if statements below
PdfPCell cell;
//On the first column (of every row)
if (0 == iColumn) {
cell = new PdfPCell(new Phrase("user " + iRow));
//On the second column of every other row starting with the first (zeroth) row
} else if ((iColumn == 1) && (iRow % 2 == 0)) {
cell = new PdfPCell();
//Have the cell span based on the current row number
cell.Colspan = iRow + 1;
//Set the color
cell.BackgroundColor = new BaseColor(System.Drawing.ColorTranslator.FromHtml("#255C8A"));
//Tell the inner for loop that we've accounted for some cells already
iColumn += iRow;
//Every other cell
} else {
cell = new PdfPCell();
}
//This is weird
cell.FixedHeight = cellWidth;
//Regardless of the above, add a cell
scheduleTable.AddCell(cell);
}
}
containerTable.AddCell(scheduleTable);
document.Add(containerTable);
document.CloseDocument();
}
}
}
Upvotes: 1