I have 2 pieces of code. The first one is working, second one is inside a loop and it doesn't show the value.
Anyone have any idea? Could it be looping is too fast for memorystream to read?
I am writing everything to a memorystream and response to download the file.
If I do it one by one as below, everything works fine.
var phraseinvoice = new Phrase();
phraseinvoice.Add(new Chunk("Invoice to:", FontFactory.GetFont(FontFactory.TIMES, 12)));
Invoicetable.AddCell(phraseinvoice);
phraseinvoice = new Phrase();
phraseinvoice.Add(new Chunk("BCD Meetings & Events Asia Pacific", FontFactory.GetFont(FontFactory.TIMES_BOLD, 12)));
PdfPCell inheader = new PdfPCell(phraseinvoice);
inheader.PaddingBottom = 4;
inheader.Border = Rectangle.NO_BORDER;
inheader.FixedHeight=20f;
Invoicetable.AddCell(inheader);
If I put them inside a array and read from a for loop the PDF will not show any text.
string[] tbText = {" ","Pte.Ltd"," ", "20 Anson Road, #06-01"," ", "Twenty Anson 079912","",
"Singapore"," "," ","Tel", "1234567", "Fax","123"," "," ","Delivery to:", "BCD Meetings & Events Asia Pacific"," ",
"Pte,Ltd"," ","20 Anson Road, #06-01"," ", "Twenty Anson 079912"," ","Singapore"};
Invoicetable.AddCell(inheader);
for (int i = 0; i < 25; i++)
{
var inputstring = tbText[i];
phraseinvoice = new Phrase();
phraseinvoice.Add(new Chunk(inputstring, FontFactory.GetFont(FontFactory.TIMES_BOLD, 12)));
PdfPCell cellbox = new PdfPCell(phraseinvoice);
cellbox = new PdfPCell(phraseinvoice);
cellbox.Border = Rectangle.NO_BORDER;
cellbox.Padding= -4;
Invoicetable.AddCell(cellbox);
}
You can see the differences between first image after -4 padding and second image without padding
You are creating a Phrase with text in a 12pt font, but you are limiting the height of the cell to 10pt. That explains why nothing is shown.
Change your code like this:
for (int i = 0; i < 25; i++)
{
var inputstring = tbText[i];
phraseinvoice = new Phrase(inputstring,
FontFactory.GetFont(FontFactory.TIMES_BOLD, 12)));
PdfPCell cellbox = new PdfPCell(phraseinvoice);
cellbox.Border = Rectangle.NO_BORDER;
cellbox.FixedHeight = 20f;
Invoicetable.AddCell(cellbox);
}
20 user units should be sufficient to show text in a 12pt font.
Update:
Another option would be to reduce the font size, for instance:
for (int i = 0; i < 25; i++)
{
var inputstring = tbText[i];
phraseinvoice = new Phrase(inputstring,
FontFactory.GetFont(FontFactory.TIMES_BOLD, 8)));
PdfPCell cellbox = new PdfPCell(phraseinvoice);
cellbox.Border = Rectangle.NO_BORDER;
cellbox.FixedHeight = 15f;
Invoicetable.AddCell(cellbox);
}
But there's more: the height needed by a Phrase in a PdfPCell depends on:
The font size,
The leading,
The ascender and descender of the font.
For instance:
for (int i = 0; i < 25; i++)
{
var inputstring = tbText[i];
phraseinvoice = new Phrase(inputstring,
FontFactory.GetFont(FontFactory.TIMES_BOLD, 12)));
PdfPCell cellbox = new PdfPCell(phraseinvoice);
cellbox.Leading = 14;
cellbox.UseAscender = true;
cellbox.UseDescender = true;
cellbox.Border = Rectangle.NO_BORDER;
cellbox.FixedHeight = 18f;
Invoicetable.AddCell(cellbox);
}
Note how we reduced the Leading from the default (1.5 times the font size) to 14, and how we told the cellBox to take the ascender and descender into account.
Looks like you are trying to add a string as a pdfpcell
var inputstring = tbText[i];
Invoicetable.AddCell(inputstring);
tbText is a string array
Related
The case is that at the beginning of Page, Elements should be drawn in one column, and after that, elements in the same page should be drawn in two columns.
So far, according to the iText example "c02e10_jekyllhydev6", I just can switch different renderers between pages, which means first applying DocumentRenderer, then add AreaBreak of Next Page, and applying ColumnDocumentRenderer in the new page.
The code:
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
Document doc = new Document(pdfDoc, PageSize.A4);
doc.SetMargins(36, 36, 36, 36);
Paragraph p = new Paragraph();
p.SetBorder(new SolidBorder(0.5f));
for (int i = 1; i <= 500; i++)
{
p.Add(new Text(i + " "));
}
doc.Add(p);
**doc.Add(new AreaBreak(AreaBreakType.NEXT_PAGE));**
PageSize ps = PageSize.A4;
var effectiveArea = doc.GetPageEffectiveArea(PageSize.A4);
float columnHeight = effectiveArea.GetHeight();
//Define column areas
Rectangle[] columns = new Rectangle[] {
new Rectangle(36, 36, 200, columnHeight),
new Rectangle(36 + 200 + 20, 36, effectiveArea.GetWidth()- 200 - 20, columnHeight)
};
ColumnDocumentRenderer renderer1 = new ColumnDocumentRenderer(doc, new Rectangle[] { columns[0] });
doc.SetRenderer(renderer1);
**doc.Add(new AreaBreak(AreaBreakType.LAST_PAGE));**
Paragraph p1 = new Paragraph();
p1.SetBorder(new SolidBorder(0.5f));
for (int i = 1; i <= 500; i++)
{
p1.Add(new Text(i + " "));
}
doc.Add(p1);
ColumnDocumentRenderer renderer2 = new ColumnDocumentRenderer(doc, new Rectangle[] { columns[1] });
doc.SetRenderer(renderer2);
Paragraph p2 = new Paragraph();
for (int i = 1; i <= 1000; i++)
{
p2.Add(new Text(i + " "));
}
doc.Add(p2);
doc.Add(new AreaBreak(AreaBreakType.NEXT_PAGE));
DocumentRenderer renderer3 = new DocumentRenderer(doc);
doc.SetRenderer(renderer3);
doc.Add(new AreaBreak(AreaBreakType.LAST_PAGE));
Paragraph p3 = new Paragraph();
for (int i = 1; i <= 1000; i++)
{
p3.Add(new Text(i + " "));
}
doc.Add(p3);
doc.Close();
If no AreaBreak added to the document, the contents with different renderers will be overlapped.
From Alexey's comment in this case, It seems possible that switching different renderers in the same page without content overlapping.
To handle this appropriately, you would have to update currentArea of the renderer you are going to switch to with the currentArea of the previous renderer you have just finished working with. You can do that by extending the standard provided renderers, or calling renderer.getCurrentArea() and modifying the bBox.
But I don't know how to achieve it according to above guides.
There is no need in ColumnDocumentRenderer in your case - that renderer was created for cases when you want to lay out your content in columns in scope of one page and then move on to the next page etc. In your case you are laying out the content in columns that span many pages and that is equivalent to just setting proper margins to the DocumentRenderer instead of passing the columns to ColumnDocumentRenderer.
To switch the renderers ad-hoc you indeed need to tweak their currentArea field and currentPageNumber as well. Please note that the solution below is not guaranteed to work in all complex cases and in all iText versions. This is merely a guideline on how to implement what you need and not a complete solution to all cases.
The helper renderer class we need is very simple - it allows customizing current area:
private class ExtendedDocumentRenderer : DocumentRenderer {
public ExtendedDocumentRenderer(Document document, RootLayoutArea currentArea) : base(document) {
this.currentArea = new RootLayoutArea(currentArea.GetPageNumber(), currentArea.GetBBox().Clone());
this.currentPageNumber = this.currentArea.GetPageNumber();
}
}
Now I've adapted your code to get rid of the ColumnDocumentRenderer and use plain DocumentRenderer instead. You just need to tweak document margins and recalculate current area (the space that is left on the page) properly:
Document doc = new Document(pdfDocument);
Paragraph p = new Paragraph();
p.SetBorder(new SolidBorder(0.5f));
for (int i = 1; i <= 500; i++)
{
p.Add(new Text(i + " "));
}
doc.Add(p);
RootLayoutArea endOfFullWidthContentArea = (RootLayoutArea) doc.GetRenderer().GetCurrentArea();
ExtendedDocumentRenderer renderer1 = new ExtendedDocumentRenderer(doc,
new RootLayoutArea(endOfFullWidthContentArea.GetPageNumber(), endOfFullWidthContentArea.GetBBox().Clone().SetWidth(200)));
doc.SetRightMargin(doc.GetRightMargin() + doc.GetPageEffectiveArea(PageSize.A4).GetWidth() - 200);
doc.SetRenderer(renderer1);
Paragraph p1 = new Paragraph();
p1.SetBorder(new SolidBorder(0.5f));
for (int i = 1; i <= 500; i++)
{
p1.Add(new Text(i + " "));
}
doc.Add(p1);
ExtendedDocumentRenderer renderer2 = new ExtendedDocumentRenderer(doc,
new RootLayoutArea(endOfFullWidthContentArea.GetPageNumber(),
endOfFullWidthContentArea.GetBBox().Clone().MoveRight(200)
.SetWidth(endOfFullWidthContentArea.GetBBox().GetWidth() - 200)));
doc.SetRightMargin(36);
doc.SetLeftMargin(200 + 36);
doc.SetRenderer(renderer2);
Paragraph p2 = new Paragraph();
for (int i = 1; i <= 1000; i++)
{
p2.Add(new Text(i + " "));
}
doc.Add(p2);
// Compute which free area is lower in the document
RootLayoutArea areaColumn1 = (RootLayoutArea) renderer1.GetCurrentArea();
RootLayoutArea areaColumn2 = (RootLayoutArea) renderer2.GetCurrentArea();
RootLayoutArea downArea = areaColumn1.GetPageNumber() > areaColumn2.GetPageNumber() ? areaColumn1 :
(areaColumn1.GetPageNumber() < areaColumn2.GetPageNumber() ? areaColumn2 :
(areaColumn1.GetBBox().GetTop() < areaColumn2.GetBBox().GetTop() ? areaColumn1 : areaColumn2));
doc.SetMargins(36, 36, 36, 36);
DocumentRenderer renderer3 = new ExtendedDocumentRenderer(doc,
new RootLayoutArea(downArea.GetPageNumber(), downArea.GetBBox().Clone().SetX(36).SetWidth(doc.GetPageEffectiveArea(PageSize.A4).GetWidth())));
doc.SetRenderer(renderer3);
Paragraph p3 = new Paragraph();
for (int i = 1; i <= 1000; i++)
{
p3.Add(new Text(i + " "));
}
doc.Add(p3);
doc.Close();
Result looks as follows:
i have some weird issue with iTextSharp.
This is the code
for (int j = 0; j < project.Slides[i].Labels.Count(); j++)
{
string pageContext = project.Slides[i].Labels[j].Text;
Response.Write(pageContext);
Response.Write("<br/>");
//string pageContext = "Some text";
paragraph = new Paragraph(pageContext,
FontFactory.GetFont("Verdana", 20));
doc.Add(paragraph);
}
in the for statement: the first line (string...) is work and get the string from list. the 2-3 lines working great, i can see the text of the string in browser. and the last paragraph not working. i see empty pages with no text. When i comment the first string and use the second one (Some text), is working and save the text. any idea??
Answer by #BrunoLowagie
BaseFont bf = BaseFont.CreateFont(Server.MapPath("~/StudioFonts/EFT_Beigale Heavy.ttf"),
BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
Font EFT_Beigale_Heavy = new Font(bf, 40);
ColumnText column = new ColumnText(writer.DirectContent);
column.SetSimpleColumn(20, 200, 300, 36);
column.RunDirection = PdfWriter.RUN_DIRECTION_RTL;
column.AddElement(new Paragraph(pageContext, EFT_Beigale_Heavy));
column.Go();
how can i set autosize on my cells, based on the max length of one input.
using (rng = workSheet.Cells["A1:G1"])
{
rng.Style.Font.Bold = true;
rng.Style.Fill.PatternType = ExcelFillStyle.Solid;
rng.Style.Fill.BackgroundColor.SetColor(Color.DarkBlue);
rng.Style.Font.Color.SetColor(Color.White);
}
using (ExcelRange col = workSheet.Cells[2, 6, 7, 7])
{
col.Style.Numberformat.Format = "yyyy-mm-dd HH:mm";
col.Style.HorizontalAlignment = ExcelHorizontalAlignment.Right;
}
for (int i = 1; i <= a; i++)
{
workSheet.Cells["A1"].Value = "RU_ID";
workSheet.Cells["B1"].Value = "COR_REQ_ID";
workSheet.Cells["C1"].Value = "RU_NAME";
workSheet.Cells["D1"].Value = "PARENT_RU_NAME";
workSheet.Cells["E1"].Value = "ADJUSTMENT_STATE";
workSheet.Cells["F1"].Value = "COR_START";
workSheet.Cells["G1"].Value = "COR_END";
}
...
rng.AutoFitColumns();
string path = #"D:\excel\test.xlsx";
Stream stream = File.Create(path);
excel.SaveAs(stream);
stream.Close();
byte[] data = File.ReadAllBytes(path);
}
The only thing that AutoFitColumn is doing is to bring the cell to the size of the header, as if i have the header as "STH" and the inputs as "Something good", "something to increase cell size" than AutoFitColumn will set the size based on "STH" not "something to increase cell size".
Thanks in advance for the help.
Look at your lines:
using (rng = workSheet.Cells["A1:G1"])
...
rng.AutoFitColumns();
Notice you are call AutoFitColumns on the range of of your headers A1:G1 so EPPlus is using only those cells to determine the width of the columns.
Just do this instead:
workSheet.Cells.AutoFitColumns();
since Cells in Epplus only contain cells with actual values so there is no real concern over efficiency.
The problem is a header file, which I have to include on each page of the pdf file generated by abcpdf.
The header file contains more than one image file and several lines of text, which varies from case to case.
The problem is that I do not know how to calculate the size of the header. I need to have its size to allocate the rectangle positions to put the rest of html file on each page together with header. I am using C#.
First off you need to create your document with enough space at the top to allow a header to be added. The settings below are for a normal A4 document with a header of about 1/5 of the page. Remember the coordinates on a PDF are from the bottom right not the top left..
//Setting to create the document using ABCPdf 8
var theDoc = new Doc();
theDoc.MediaBox.String = "A4";
theDoc.HtmlOptions.PageCacheEnabled = false;
theDoc.HtmlOptions.ImageQuality = 101;
theDoc.Rect.Width = 719;
theDoc.Rect.Height = 590;
theDoc.Rect.Position(2, 70);
theDoc.HtmlOptions.Engine = EngineType.Gecko;
The code below out puts a header across each page on the document, with a header image then a colored box under the image with some custom text in.
The header image in this case is 1710 x 381 to keep the resolution of the image as high as possible to stop it looking fuzzy when printed.
private static Doc AddHeader(Doc theDoc)
{
int theCount = theDoc.PageCount;
int i = 0;
//Image header
for (i = 1; i <= theCount; i++)
{
theDoc.Rect.Width = 590;
theDoc.Rect.Height = 140;
theDoc.Rect.Position(0, 706);
theDoc.PageNumber = i;
string imagefilePath = HttpContext.Current.Server.MapPath("/images/pdf/pdf-header.png");
Bitmap myBmp = (Bitmap)Bitmap.FromFile(imagefilePath);
theDoc.AddImage(myBmp);
}
//Blue header box
for (i = 2; i <= theCount; i++)
{
theDoc.Rect.String = "20 15 590 50";
theDoc.Rect.Position(13, 672);
System.Drawing.Color c = System.Drawing.ColorTranslator.FromHtml("#468DCB");
theDoc.Color.Color = c;
theDoc.PageNumber = i;
theDoc.FillRect();
}
//Blue header text
for (i = 2; i <= theCount; i++)
{
theDoc.Rect.String = "20 15 586 50";
theDoc.Rect.Position(25, 660);
System.Drawing.Color cText = System.Drawing.ColorTranslator.FromHtml("#ffffff");
theDoc.Color.Color = cText;
string theFont = "Century Gothic";
theDoc.Font = theDoc.AddFont(theFont);
theDoc.FontSize = 14;
theDoc.PageNumber = i;
theDoc.AddText("Your Text Here");
}
return theDoc;
}
I would like to create a main overview chart with asp:chart control, like this:
Instead of Andrew, etc. it would be fiscal years (2009, 2010, 2011, etc.) and the products would be the 4 types of costs.
But how do I do this with a list of custom objects that are contstructed like this:
List< Cost_cost > listOfCosts
Cost
Type (can be one of four types)
Amount (float)
Fiscal Year
Anybody got a link or tips on how to handle this?
Found a solution, it's partialy hard coded, i.e., the types of costs but since it needs to be uploaded by the day after tomorrow, it'll do.
The following code of course is after I created Chart1, the mainlegend and area and some styling stuff:
//Set the amount of the four series to zero
float totalAmountHousing = 0, totalAmountPersonnel = 0, totalAmountServices = 0, totalAmountIT = 0;
//Create the four series per year
Series sr = new Series(); Series sr2 = new Series(); Series sr3 = new Series(); Series sr4 = new Series();
//Set the series to the same chart area
sr.ChartArea = "mainArea"; sr2.ChartArea = "mainArea"; sr3.ChartArea = "mainArea"; sr4.ChartArea = "mainArea";
//Set them to the same legend
sr.Legend = "mainLegend"; sr2.Legend = "mainLegend"; sr3.Legend = "mainLegend"; sr4.Legend = "mainLegend";
//Set the names of the 4 series
sr.Name = "Housing"; sr2.Name = "IT"; sr3.Name = "Services"; sr4.Name = "Personnel";
//Add the series to the chart
Chart1.Series.Add(sr); Chart1.Series.Add(sr2); Chart1.Series.Add(sr3); Chart1.Series.Add(sr4);
//Set drawing style to cylinder of the four costs
Chart1.Series["Housing"]["DrawingStyle"] = "Cylinder";
Chart1.Series["IT"]["DrawingStyle"] = "Cylinder";
Chart1.Series["Services"]["DrawingStyle"] = "Cylinder";
Chart1.Series["Personnel"]["DrawingStyle"] = "Cylinder";
for (int i = 0; i < listOfFiscalYears.Count; i++) {
//generate some point for the chart
for (int j = 0; j < listOfCosts.Count; j++) {
if ((listOfCosts[j].Type).ToLower() == "housing" && listOfCosts[j].Cost_fiscalYear.Year == int.Parse(listOfFiscalYears[i].ToString())) totalAmountHousing += (float)listOfCosts[j].Amount;
if ((listOfCosts[j].Type).ToLower() == "it" && listOfCosts[j].Cost_fiscalYear.Year == int.Parse(listOfFiscalYears[i].ToString())) totalAmountIT += (float)listOfCosts[j].Amount;
if ((listOfCosts[j].Type).ToLower() == "services" && listOfCosts[j].Cost_fiscalYear.Year == int.Parse(listOfFiscalYears[i].ToString())) totalAmountServices += (float)listOfCosts[j].Amount;
if ((listOfCosts[j].Type).ToLower() == "personnel" && listOfCosts[j].Cost_fiscalYear.Year == int.Parse(listOfFiscalYears[i].ToString())) totalAmountPersonnel += (float)listOfCosts[j].Amount;
}
Chart1.Series["Housing"].Points.Add(totalAmountHousing);
Chart1.Series["IT"].Points.Add(totalAmountIT);
Chart1.Series["Services"].Points.Add(totalAmountServices);
Chart1.Series["Personnel"].Points.Add(totalAmountPersonnel);
Chart1.ChartAreas["mainArea"].AxisX.Interval = 1;
//Add custom label to the X axis
Chart1.ChartAreas[0].AxisX.CustomLabels.Add(new CustomLabel(i, i + 2, (listOfFiscalYears[i].ToString()), 0, LabelMarkStyle.None));
//Reset the total cost after they have been added for the year
totalAmountHousing = 0; totalAmountPersonnel = 0; totalAmountServices = 0; totalAmountIT = 0;
}