This question already has an answer here:
Odd Numbered Cell Not Added To Pdf
(1 answer)
Closed 7 years ago.
I'm trying to create table without borders with 4 columns and 2 rows on top of my PDF document. The problem is that the 2nd row won't be written. This is my code:
float[] columnWidths = { 2, 1, 1, 1};
PdfPTable table = new PdfPTable(columnWidths);
table.WidthPercentage = 100;
if (...) //true
{
if (...) //true
{
PdfPCell p = new PdfPCell(new Phrase("AAA:_______________",infoFont));
p.BorderWidth = 0;
table.AddCell(p); // fixed pos. 1st col,1st row
}
if (...) //true
{
PdfPCell p = new PdfPCell(new Phrase("BBB:_____", infoFont));
p.BorderWidth = 0;
table.AddCell(p); // fixed pos. 2nd col,1st row
}
if (...) //true
{
PdfPCell p = new PdfPCell(new Phrase("CCC:_____", infoFont));
p.BorderWidth = 0;
table.AddCell(p); // fixed pos. 3rd col,1st row
}
if (...) //true
{
PdfPCell p = new PdfPCell(new Phrase("DDD:_____", infoFont));
p.BorderWidth = 0;
table.AddCell(p); // fixed pos. 4th col,1st row
}
}
if (...) //true
{
if (...) //true
{
PdfPCell p = new PdfPCell(new Phrase("EEE: " + eee));
p.BorderWidth = 0;
table.AddCell(p); // fixed pos. 1st col,2nd row
}
if (...) //true
{
PdfPCell p = new PdfPCell(new Phrase("FFF: " + fff));
p.BorderWidth = 0;
table.AddCell(p); // fixed pos. 2nd col,2nd row
}
if (...) //true
{
PdfPCell p = new PdfPCell(new Phrase("GGG: " + ggg));
p.BorderWidth = 0;
table.AddCell(p); // fixed pos. 3rd col,2nd row
}
if (...) //true
{
PdfPCell p = new PdfPCell(new Phrase("HHH:___________________"));
p.BorderWidth = 0;
table.AddCell(p); // fixed pos. 4th col,2nd row
}
}
document.Add(table);
How can I deal with this? And the 2nd question: can I have fixed position for every if condition (check the comments in the code) so when one if-condition in first row is not true then that cell should be empty?
I assume that you've simplified your code to the extent that the snippet you share is no longer consistent with your own code. You are creating a table with 4 columns. If you add 4 cells, one row will be rendered. If you add 8 cells, two rows will be rendered. However: if you only add 7 cells, then a single row will be added. The 3 cells in the incomplete row will be omitted because iText only renders complete rows.
See also How to generate pdf if our column less than the declared table column and ItextSharp, number of Cells not dividable by the length of the row and Odd Numbered Cell Not Added To Pdf and PdfTable: last cell is not visible and ...
This explains why the second row isn't shown. Add the following line to see if this fixes the problem:
table.CompleteRow();
As for your other question: you can always add an empty cell like this:
PdfPCell cell = new PdfPCell();
if (someCondition) {
cell.addElement(new Paragraph("AAA"));
}
table.addCell(cell);
Finally, there's another error in your code. This doesn't make any sense:
p.BorderWidth = 0;
A border width of 0 doesn't mean that no border will be shown. As explained many times before ISO-32000-1 defines a line with 0 width as a line of which the width is equal to the minimal width that can be displayed by the device. If you don't want any border use:
p.Border = PdfPCell.NO_BORDER;
Finally, I need to ask you a favor: we've redesigned the iText web site and we released it on Thanksgiving. We now notice that we don't get as many visits as we used to before the change. Given the fact that all the information you needed can be found on the online documentation and given the fact that you still needed to ask the question, we'd like to know what is wrong with the web site. Is there something we can do to improve the content? What could be the reason that drives people away from our web site? Why are you asking so many questions that are already answered in the official documentation? Do we have too much content now?
Related
I want to display the sequence as AA, AB, AC and so on.
This sequence should be applied to PDF rows line by line using ItextSharp Library and the Values comes from SQL DB.
eg of sequence-->
1st record AA
2nd record AB
3rd record AC
... and so on
I have code to generate sequence of AA, AB, AC .... so on, But the existing code has many tables with some number of rows, So if first table has 5 rows then the sequence is applied for 5 rows as AA, AB, AC, AD,AE and loop ends for table1, when table2 loop starts the sequence not starting from AF but it is taking as new table and again sequence repetition starting as AA, AB, AC upto so on and for next table again the sequence starts from AA,AB,AC....,
The Project Existing code using loops to fetch the data apply to PDF from DB, Whenever new table comes from DB new sequence is getting started.
I am unable solve this problem please someone helpme to overcome this.
String index = "";
PdfPTable table = new PdfPTable(columnWidth.Count()) { TotalWidth = TABLE_WIDTH, LockedWidth = true };
index = GetIndex(table.Size);
private static string mColumnLetters = "zabcdefghijklmnopqrstuvwxyz";
public static string GetIndex(int ColumnIndex)
{
int ModOf26, Subtract;
StringBuilder NumberInLetters = new StringBuilder();
ColumnIndex += 26;
while (ColumnIndex > 0)
{
if (ColumnIndex <= 26)
{
ModOf26 = ColumnIndex;
NumberInLetters.Insert(0, mColumnLetters.Substring(ModOf26, 1));
ColumnIndex = 0;
}
else
{
ModOf26 = ColumnIndex % 26;
Subtract = (ModOf26 == 0) ? 26 : ModOf26;
ColumnIndex = (ColumnIndex - Subtract) / 26;
NumberInLetters.Insert(0, mColumnLetters.Substring(ModOf26, 1));
}
}
return NumberInLetters.ToString().ToUpper();
}
==>Please help me to get the program to display AA, AB, AC, etc without any splits.
Getindex(Table.Size)==> here the input parameter making problem i think Instead Table.Size which input should i pass if i have to overcome Splits and repeated seq generation.
==>Can anyone please help me by spending sometime on this regard
Your GetIndex method returns, for increasing values of value, starting from 1:
1: A
2: B
...
26: Z
27: AA
...
52: AZ
53: BA
etc
So, if you make sure to start with 27 for value, you could keep that method as is.
I'm not sure why you have an issue with table splitting. You should just add content to a single table, regardless of splitting. iText will take care of the splitting.
Document doc = new Document();
Stream outfile = new FileStream("SO66781099.pdf", FileMode.Create);
PdfWriter w = PdfWriter.GetInstance(doc, outfile);
doc.Open();
PdfPTable table = new PdfPTable(1);
for (int i = 1; i < 100; i++)
{
// first call to GetIndex is for 27
PdfPCell cell = new PdfPCell(new Phrase(GetIndex(i + 26)));
cell.FixedHeight = 50;
table.AddCell(cell);
}
doc.Add(table);
doc.Close();
End of page 1, start of page 2:
Text in a merged cell across rows is cut off because Excel ignores merged cells when automatically resizing a row.
How can I resize cell height to its contents for rows that resize doesn't work for?
I am posting this out there to help others that had this problem. I posted a solution as an answer.
For this solution, I am only showing code related to resizing rows not displaying data
Solution:
///
/// Merged Row Model Psuedo Code
///
MergedRow {
// Fields merged across rows
...
// list of rows with non merged data
list<indvidulerow> data
}
///
/// Code to find rows with merged cells.
///
... // worksheet prep
var mergedRows = new Dictionary<int, MergedRow>();
... // begin generating rows
...
// code generating the first merged cell of a row
using (var r = sheet.Cells[rowIndex, 1, rowIndex+ mergedRow.Data.Count - 1, 1]){
if(mergedRow.Data.count>1){
r.Merge=true;
mergedRows.Add(rowIndex, mergedRow);
}
... // code for remainder of of cell
///
/// Code to Resize Rows. Making last row expand enough to see
/// all content in merged cells
///
foreach (var firstRowIndex in mergedRows.Keys){
var numRowsMerged = mergedRows[firstRowIndex].Data.Count;
var columnHeights = new List<ColumnHeightCalcModel>();
for (var colIndex = 0; colIndex < totalColumns; colIndex++){
var calcModel = new ColumnHeightCalcModel();
var combinedHeight = 0.0;
var lastRowHeight = 0.0;
for (rowIndex = 0; rowIndex < numRowsMerged; rowIndex++){
var cell = sheet.Cells[firstRowIndex + rowIndex, colIndex + 1];
var cellText = cell.Text;
var cellmerged = cell.Merge;
var cellWidth = sheet.Column(colIndex+1).Width;
var font = cell.Style.Font;
if (string.IsNullOrEmpty(cellText)) combinedHeight += 0.0;
var bitmap =new Bitmap(1,1);
var graphics = Graphics.FromImage(bitmap);
var pixelWidth = Convert.ToInt32(cellWidth * 6.0); //6.0 pixels per excel column width
var drawingFont = new Font(font.Name, font.Size);
var size = graphics.MeasureString(cellText, drawingFont, pixelWidth);
//72 DPI and 96 points per inch. Excel height in points with max of 409 per Excel requirements.
combinedHeight += Math.Min(Convert.ToDouble(size.Height) * 72 / 96, 409);
if (cellmerged) break;
lastRowHeight = Math.Min(Convert.ToDouble(size.Height) * 72 / 96, 409);
}
calcModel.TotalCombinedHeight = combinedHeight;
calcModel.LastRowHeight = lastRowHeight;
columnHeights.Add(calcModel);
}
var row = sheet.Row(firstRowIndex + numRowsMerged - 1);
row.CustomHeight = true;
var maxCombo = columnHeights.Max(col => col.TotalCombinedHeight);
var maxLast = columnHeights.Max(col => col.LastRowHeight);
row.Height = maxCombo - maxLast;
}
End Solution
Links that helped me find this solution
The following link was for Merged columns but it helped with merged rows.
Autofit Row Height of Merged Cell in EPPlus
Hello well i have one question why the last row never gets read? It dosenĀ“t matter if its only one row in the excel file or 100 rows. The last row never shows up in the List. And i have no clue why....
Here is my Excel File:
and this is my method:
public List<string> getListData(bool skipFirstRow, int numberOfColumns, string filepath)
{
int startpoint = 1;
int cell = 1;
int row = 1;
List<string> stringList = new List<string>();
//Open Excel (Application)
var excelApplication = openExcelApplication();
//Open Excel File
Excel.Workbook excelWorkbook = excelApplication.Workbooks.Open(filepath);
//Get the Worksheets from the file
Excel.Sheets excelSheets = excelWorkbook.Worksheets;
//Select the first Worksheet
Excel.Worksheet worksheet = (Excel.Worksheet)excelSheets.get_Item(1);
if (skipFirstRow == true)
{
startpoint = 2;
}
Excel.Range range = worksheet.get_Range("A" + Convert.ToString(startpoint), Missing.Value);
while ((range.Cells[startpoint, cell] as Excel.Range).Value2 != null)
{
for (int i = 1; i <= numberOfColumns + 1; i++)
{
string sValue = (range.Cells[row, cell] as Excel.Range).Value2.ToString();
stringList.Add(sValue);
cell++;
}
startpoint++;
cell = 1;
row++;
}
closeExcelApplication(excelApplication);
var result =
stringList
.Select((item, index) => new { Item = item, Index = index })
.GroupBy(x => x.Index / numberOfColumns)
.Select(g => string.Join(";", g.Select(x => x.Item)))
.ToList();
return result;
}
I tried it with the debugger and even google. Then i tried it with the last used row stuff but didnt worked.
Excel.Range last = worksheet.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
Excel.Range range = worksheet.get_Range("A1", last);
int lastUsedRow = last.Row;
int lastUsedColumn = last.Column;
Any help or advise would be great so thanks for your time and help.
Your algorithm is buggy.
Let's see what happens when skipFirstRow is true and your Excel sheet has three rows 1, 2 and 3. At the start of the while loop, we have the following situation:
startpoint = 2
row = 1
During the first iteration, your while loop reads the contents of row 1. After the iteration, we have the following situation:
startpoint = 3
row = 2
During the second iteration, your while loop reads the contents of row 2. After the iteration, we have the following situation:
startpoint = 4
row = 3
Since range.Cells[startpoint, cell] is empty, your code stops here. Rows 1 and 2 have been read, row 3 has been ignored.
As you can see, the reason for your problem is that you check the row in startpoint and read the row in row, and when those two differ, you have a problem. Suggested solution: Drop the startpoint variable and use row instead.
The excel sheet display first row number as 1
but internally it starts from 0, may be it is reading all the data,put different test data on last column
How can I set two tables parallelly in a document
My sample code for generate pdf is,
Document doc = new Document(new Rectangle(288f, 144f), 10, 10, 10, 10);
doc.SetPageSize(iTextSharp.text.PageSize.A4.Rotate());
PdfWriter writer = PdfWriter.GetInstance(doc, Response.OutputStream);
doc.Open();
PdfPTable table = new PdfPTable(3);
table.TotalWidth = 144f;
table.LockedWidth = true;
PdfPCell cell = new PdfPCell(new Phrase("This is table 1"));
cell.Colspan = 3;
cell.HorizontalAlignment = 1;
table.AddCell(cell);
table.AddCell("Col 1 Row 1");
table.AddCell("Col 2 Row 1");
table.AddCell("Col 3 Row 1");
table.AddCell("Col 1 Row 2");
table.AddCell("Col 2 Row 2");
table.AddCell("Col 3 Row 2");
table.WriteSelectedRows(0, -1, doc.Left, doc.Top, writer.DirectContent);
table = new PdfPTable(3);
table.TotalWidth = 144f;
table.LockedWidth = true;
cell = new PdfPCell(new Phrase("This is table 2"));
cell.Colspan = 3;
cell.HorizontalAlignment = 1;
table.AddCell(cell);
table.AddCell("Col 1 Row 1");
table.AddCell("Col 2 Row 1");
table.AddCell("Col 3 Row 1");
table.AddCell("Col 1 Row 2");
table.AddCell("Col 2 Row 2");
table.AddCell("Col 3 Row 2");
table.WriteSelectedRows(0, -1, doc.Left + 200, doc.Top, writer.DirectContent);
doc.Close();
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment;" + "filename=Sample .pdf");
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Write(doc);
Response.End();
When run this code,pdf downloads but shows error message "Failed to load PDF document".Please help me to solve the error and get the expected output
There are a number of issues in your code. The ones immediately visible:
You don't close the document doc but only at closing time certain important parts of the PDF are created, in particular the cross reference table. Thus, you have to close the document as soon as possible after completing its content.
You try to write the doc to the response:
Response.Write(doc);
This is wrong, you have to direct the output of your PdfWriter to the response. You actually do this, too, kind of trying to transmit the PDF twice:
PdfWriter writer = PdfWriter.GetInstance(doc, Response.OutputStream);
But:
You change response properties after starting to write a response, i.e. you first create a PDF streaming it to Response.OutputStream and only thereafter change the content type, content disposition, and cache headers.
This quite likely either makes the Response ignore your settings or forget what has been streamed into it up to then.
Until you have fixed these issues, I would propose you create a simple HelloWorld PDF instead of your parallel tables to not have problems in PDF generation and problems in the use of web service classes like Response intermingle with each other.
I'm dynamically creating a HyperLink with an image, and it being entered into every cell from a dataset.
Well for some reason, the images are not showing up in any of the cells, the link is there but the image is not and I have no idea why.
When I stepped through the code, the ImageUrl is correct, and when I copy the path and paste in explorer the image shows up, but its not showing up in the cells.
The code is...
for (cellCtr = 1; cellCtr <= 3; cellCtr++)
{
HyperLink link = new HyperLink();
// Create a new cell and add it to the row.
TableCell tCell = new TableCell();
/* If the rowcounter is equal to the record numbers
* then it has to break because if not it will throw an error
* saying that there is no row at ending position */
if (rowCtr == rN)
break;
string subjectid = myDs.Tables[0].Rows[rowCtr]["SubjectID"].ToString();
string iconUrl = myDs.Tables[0].Rows[rowCtr]["IconUrl"].ToString();
link.ID = subjectid;
link.ImageUrl = iconUrl;
link.NavigateUrl = "~/WebForm2.aspx";
tCell.Controls.Add(link);
tRow.Cells.Add(tCell);
rowCtr++;
/* If the cellcount is 3 then it needs to break, if not then
* you'll miss every 4rth record, don't know why. But this works */
if (cellCtr == 3)
{
rowCtr = rowCtr - 1;
break;
}
}
I'm at a loss for why the images won't appear...
Thanks