iTextSharp - Page Layout with Columns in Asp.Net

Description:-

Most often, when working with columns you will want to add multiple columns for text layout, similar to a newspaper. ITextSharp has a MultiColumnText object which makes this pretty simple. All you need to tell it is where the leftmost column should start from along the X-axis, where that rightmost column should end, what space you would like between the columns and how many columns you want. The following adds 2 columns to a page, and then adds a paragraph 8 times:  

string pdfpath = Server.MapPath("PDFs");
string imagepath = Server.MapPath("Columns");
Document doc = newDocument();
try
{
  PdfWriter.GetInstance(doc, newFileStream(pdfpath + "/Columns.pdf", FileMode.Create));
  doc.Open();
  Paragraph heading = newParagraph("Page Heading", newFont(Font.HELVETICA, 28f, Font.BOLD));
  heading.SpacingAfter = 18f;
  doc.Add(heading);
  string text = @"Loremipsum dolor sit amet, consectetueradipiscingelit. Suspendisseblanditblanditturpis.Nam in lectusut dolor consectetuerbibendum.Morbinequeipsum, laoreet id; dignissimet, viverra id, mauris. Nullamauriselit, consectetuer sit amet, accumsaneget, congue ac, libero. Vivamussuscipit.Nuncdignissimconsectetuerlectus.Fusceelit nisi; commodonon, facilisisquis, hendreriteu, dolor? Suspendisseeleifend nisi ut magna.Phasellus id lectus! Vivamuslaoreetenimet dolor. Integer arcumauris, ultriciesvel, portaquis, venenatis at, libero.Donecnibhest, adipiscing et, ullamcorper vitae, placerat at, diam. Integer ac turpisvel ligula rutrumauctor! Morbiegestaserat sit amet diam. Ututipsum? Aliquam non sem. Nullarisuseros, mollisquis, blanditut; luctuseget, urna.Vestibulumvestibulumdapibuserat.Proinegestasleo a metus?";
  MultiColumnText columns = newMultiColumnText();

  //float left, float right, float gutterwidth, int numcolumns
  columns.AddRegularColumns(36f, doc.PageSize.Width - 36f, 24f, 2);
 
  Paragraphpara = newParagraph(text, newFont(Font.HELVETICA, 8f));
  para.SpacingAfter = 9f;
  para.Alignment = Element.ALIGN_JUSTIFIED;
  for (int i = 0; i < 8; i++)
  {
    columns.AddElement(para);
  }
 
  doc.Add(columns);
}
catch (Exception ex)
{
  //Log(ex.Message);
}
finally
{
  doc.Close();
}  

The result shows how the text just flowed from one column to another once the first column was filled.

AddRegularColumns() will set each column at exactly the same width. AddSimpleColumn() allows you to specify the width of individual columns, which means that you can work with irregularly sized columns:  

columns.AddSimpleColumn(36f, 170f);
columns.AddSimpleColumn(194f, doc.PageSize.Width - 36f);  

The code above replaces the AddRegularColumn() call in the preceding block and creates two separate column objects. The first starts at the left margin (36 points in from the left edge) and is 2 inches wide (170 - 36 = 144 points). The second column starts 24 points (1/3 of an inch) further over and butts up against the right hand margin.


Adding other elements such as images and tables is straightforward: 

string pdfpath = Server.MapPath("PDFs");
string pdfpath = Server.MapPath("PDFs");
string imagepath = Server.MapPath("Images");
Document doc = new Document();
try
{
  PdfWriter.GetInstance(doc, new FileStream(pdfpath + "/Columns1.pdf", FileMode.Create));
  doc.Open();
  Paragraph heading = new Paragraph("Page Heading", newFont(Font.HELVETICA, 28f, Font.BOLD));
  heading.SpacingAfter = 18f;
  doc.Add(heading);
  string text = @"Loremipsum dolor sit amet, consectetueradipiscingelit. Suspendisseblanditblanditturpis.Nam in lectusut dolor consectetuerbibendum.Morbinequeipsum, laoreet id; dignissimet, viverra id, mauris. Nullamauriselit, consectetuer sit amet, accumsaneget, congue ac, libero. Vivamussuscipit.Nuncdignissimconsectetuerlectus.Fusceelit nisi; commodonon, facilisisquis, hendreriteu, dolor? Suspendisseeleifend nisi ut magna.Phasellus id lectus! Vivamuslaoreetenimet dolor. Integer arcumauris, ultriciesvel, portaquis, venenatis at, libero.Donecnibhest, adipiscing et, ullamcorper vitae, placerat at, diam. Integer ac turpisvel ligula rutrumauctor! Morbiegestaserat sit amet diam. Ututipsum? Aliquam non sem. Nullarisuseros, mollisquis, blanditut; luctuseget, urna.Vestibulumvestibulumdapibuserat.Proinegestasleo a metus?";
  MultiColumnText columns = new MultiColumnText();
  columns.AddSimpleColumn(36f, 336f);
  columns.AddSimpleColumn(360f, doc.PageSize.Width - 36f);

  Paragraphpara = new Paragraph(text, new Font(Font.HELVETICA, 8f));
  para.SpacingAfter = 9f;
  para.Alignment = Element.ALIGN_JUSTIFIED;

  PdfPTable table = new PdfPTable(3);
  float[] widths = new float[] { 1f, 1f, 1f };
  table.TotalWidth = 300f;
  table.LockedWidth = true;
  table.SetWidths(widths);
  PdfPCell cell = new PdfPCell(newPhrase("Header spanning 3 columns"));
  cell.Colspan = 3;
  cell.HorizontalAlignment = 0;
  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");

  iTextSharp.text.Image jpg = iTextSharp.text.Image.GetInstance(imagepath + "/Jellyfish.jpg");
  jpg.ScaleToFit(300f, 300f);
  jpg.SpacingAfter = 12f;
  jpg.SpacingBefore = 12f;

  columns.AddElement(para);
  columns.AddElement(table);
  columns.AddElement(jpg);
  columns.AddElement(para);
  columns.AddElement(para);
  columns.AddElement(para);
  columns.AddElement(para);
  doc.Add(columns);
}
catch (Exception ex)
{
  //Log(ex.Message);
}
finally
{
  doc.Close();
} 

The example above takes a table and images from previous tutorials, and adds them together with the paragraph to the columns. the first column is 300 points wide, and the second one takes up the remainder of the page width.

MultiColumnText is great for creating columns without too much code, but it lacks an element of control. ColumnText provides much more, but requires more code. The following sample shows ColumnText being used to create irregular columns, in that the first one has chunk taken from the top left corner to accommodate an image which is shown here in the resulting PDF:


string pdfpath = Server.MapPath("PDFs");
string imagepath = Server.MapPath("Images");
FontFactory.RegisterDirectory("C:\\WINDOWS\\Fonts");

Document doc = new Document();
Font font1 = new Font(FontFactory.GetFont("adobe garamond pro", 36f, Color.GRAY));
Font font2 = new Font(Font.TIMES_ROMAN, 9f);
doc.SetMargins(45f, 45f, 60f, 60f);
try
{
  FileStream output = new FileStream(pdfpath + "/IrregularColumns.pdf", FileMode.Create);
  PdfWriter writer = PdfWriter.GetInstance(doc, output);
  doc.Open();
  PdfContentBytecb = writer.DirectContent;
  ColumnTextct = new ColumnText(cb);
  ct.Alignment = Element.ALIGN_JUSTIFIED;

  Paragraph heading = new Paragraph("Chapter 1", font1);
  heading.Leading = 40f;
  doc.Add(heading);
  iTextSharp.text.Image L = iTextSharp.text.Image.GetInstance(imagepath + "/ajax-loader(1).gif");
  L.SetAbsolutePosition(doc.Left, doc.Top - 180);
  doc.Add(L);

  ct.AddText(new Phrase("oremipsum dolor sit amet, consectetueradipiscingelit. Suspendisseblanditblanditturpis.Nam in lectusut dolor consectetuerbibendum.Morbinequeipsum, laoreet id; dignissimet, viverra id, mauris. Nullamauriselit, consectetuer sit amet, accumsaneget, congue ac, libero. Vivamussuscipit.Nuncdignissimconsectetuerlectus.Fusceelit nisi; commodonon, facilisisquis, hendreriteu, dolor? Suspendisseeleifend nisi ut magna.Phasellus id lectus! Vivamuslaoreetenimet dolor. Integer arcumauris, ultriciesvel, portaquis, venenatis at, libero.Donecnibhest, adipiscing et, ullamcorper vitae, placerat at, diam. Integer ac turpisvel ligula rutrumauctor! Morbiegestaserat sit amet diam. Ututipsum? Aliquam non sem. Nullarisuseros, mollisquis, blanditut; luctuseget, urna.Vestibulumvestibulumdapibuserat.Proinegestasleo a metus?\n\n", font2));
  
  ct.AddText(new Phrase("Vivamusenim nisi, mollis in, sodalesvel, convallis a, augue? Proin non enim.Nullamelementumeuismoderat.Aliquammalesuadaeleifend quam! Nullafacilisi.Aeneanutturpis ac esttempormalesuada. Maecenas scelerisqueorci sit ametauguelaoreet tempus. Duisinterdumestuteros. Fusce dictum dignissimelit.Morbi at dolor.Fusce magna.Nullatellusturpis, mattisut, eleifend a, adipiscing vitae, mauris.Pellentesquemattislobortis mi.\n\n", font2));

  ct.AddText(new Phrase("Nullam sit ametmetusscelerisquediamhendreritporttitor. Aeneanpellentesque, lorem a consectetuerconsectetuer, nuncmetushendrerit quam, mattisultricesloremtelluslaciniamassa. Aliquam sit ametodio. Proinmauris.Integer dictum quam a quam accumsanlacinia.Pellentesquepulvinarfeugiateros.Suspendisserhoncus.Sedconsectetuerleoeu nisi. Suspendissemassa! Sedsuscipit lacus sit ametelit! Aliquamsollicitudincondimentumturpis.Nuncutaugue! Maecenas eueros.Morbi in urnaconsectetueripsumvehiculatristique.\n\n", font2));
  
  ct.AddText(new Phrase("Donecimperdietpurusvel ligula. Vestibulumtempor, odioutscelerisqueeleifend, nullasapienlaoreet dui; velaliquamarculiberoeu ante.Curabiturrutrumtristique mi. Sedlobortisiaculisarcu.Suspendissemauris.Aliquammetus lacus, elementumquis, mollis non, consequatnec, tortor.\n", font2));

  ct.AddText(new Phrase("Quisque id diam. Utegestasleo a elit. Nulla in metus.Aliquamiaculisturpis non augue.Donec a nunc?Phaselluseueros.Nam luctus.Duiseu mi. Utmollis.Nullafacilisi.Loremipsumdolor sitamet, consectetueradipiscingelit. Class aptenttacitisociosquadlitoratorquent per conubia nostra, per inceptoshimenaeos.Aeneanpede.Nullafacilisi.Vestibulummattisadipiscingnulla.Praesentorci ante, mattis in, cursuseget, posueresed, mauris.\n\n", font2));

  ct.AddText(new Phrase("Nullafacilisi. Nuncaccumsanrisusaliquet quam. Nam pellentesque! Aeneanporttitor.Aeneancongueullamcorpervelit.Phasellussuscipitplacerattellus.Vivamusdiamodio, tempus quis, suscipit a, dictum eu; lectus.Sedvelnisl.Utinterdumurnaeunibh.Praesentvehicula, orci id venenatisultrices, maurisurnamollis lacus, etblanditodio magna at enim. Pellentesqueloremfelis, ultricesquis, gravidased, pharetra vitae, quam.Maurisliberoipsum, pharetra a, faucibusaliquet, pellentesque in, mauris.Cras magna neque, interdumvel, variusnec; vulputate at, erat. Quisque vitae urna.Suspendissepotenti.Nullaluctuspurus at turpis! Vestibulum vitae dui.Nullamodio.\n\n", font2));
  
  ct.AddText(new Phrase("Vestibulum ante ipsumprimis in faucibusorciluctus et ultricesposuerecubiliaCurae; Sedeget mi at semiaculishendrerit. Nullafacilisi.Etiamsedelit.In viverradapibussapien.Aliquam nisi justo, ornarenon, ultricies vitae, aliquam sit amet, risus! Cum sociisnatoquepenatibusetmagnis dis parturient montes, nasceturridiculus mus. Phasellusrisus. Vestibulumpretiumaugue non mi. Sed magna.In hachabitasseplateadictumst.Quisquemassa. Etiamviverradiampharetra ante.Phasellusfringillavelitutodio! Nam necnulla.\n\n", font2));

  ct.AddText(new Phrase("Integer augue. Morbiorci.Sedquisnibh.Nullam ac magna id leofaucibusornare. Vestibulumegetlectus sit ametnuncfacilisisbibendum. Donecadipiscingconvallis mi. Cumsociisnatoquepenatibus et magnis dis parturient montes, nasceturridiculus mus. Vivamusenim. Mauris ligula lorem, pellentesquequis, semper sed, tristique sit amet, justo.Suspendissepotenti.Proin vitae enim.Morbi et nisi sit ametsapienve.\n\n", font2));

  float gutter = 15f;
  float colwidth = (doc.Right - doc.Left - gutter) / 2;
  float[] left = { doc.Left + 90f , doc.Top - 80f,
  doc.Left + 90f, doc.Top - 170f,
  doc.Left, doc.Top - 170f,
  doc.Left ,doc.Bottom };

  float[] right = { doc.Left + colwidth, doc.Top - 80f,
  doc.Left + colwidth, doc.Bottom };

  float[] left2 = { doc.Right - colwidth, doc.Top - 80f,
  doc.Right - colwidth, doc.Bottom };

  float[] right2 = {doc.Right, doc.Top - 80f,
  doc.Right, doc.Bottom };

  int status = 0;
  int i = 0;
  //Checks the value of status to determine if there is more text
  //If there is, status is 2, which is the value of NO_MORE_COLUMN
  while (ColumnText.HasMoreText(status))
  {
    if (i == 0)
    {
      //Writing the first column
      ct.SetColumns(left, right);
      i++;
    }
    else
    {
      //write the second column
      ct.SetColumns(left2, right2);
    }
    //Needs to be here to prevent app from hanging
    ct.YLine = doc.Top - 80f;
    //Commit the content of the ColumnText to the document
    //ColumnText.Go() returns NO_MORE_TEXT (1) and/or NO_MORE_COLUMN (2)
    //In other words, it fills the column until it has either run out of column, or text, or both
    status = ct.Go();
  }
}
catch (Exception ex)
{
  //Log(ex.Message);
}
finally
{
  doc.Close();
}

ColumnText requires that you need a PDFContentByte object. This is nearly always the case when you want to place stuff at fixed positions. The code above starts by defining a document object, and then creating some fonts to work with, as well as setting the margins of the document (which needs to be done before the document is opened to take effect). A PdfWriter object is created so that the PDFContentByte object can be instantiated from its DirectContent property. Then a ColumnText object is created using the PDFContentByte. A heading is added, followed by the illustrated capital "L", which starts the Chapter. This is followed by a number of Phrases, set out as paragraphs.

So, now the ColumnText object has its text content, but nowhere to put it yet, so the two columns are created. The first array of floats defines the irregular shape of the left hand side fo the first column which has to the top corner chopped out of it to make way for the image. The second array defines the straight right hand edge. The third and fourth arrays take care of the regularly shaped second column. Two int variables are created to hold the value of the status of the column with regard to whether there is any more text to be added (status), and then the number of the column that is currently being worked on (i).

ColumnText.HasMoreText(status) is a convenience method that takes an int as a parameter. It examines the value of the parameter to see if there is any more text to be added and returns true if there is. The value that returns false is 1. It is initialised at 0 to start, so HasMoreText returns true. Since i is also 0, the code executes to add the first column, then the YLine is set to the top of the column. This must be done, otherwise the application will just spin until the execution timeout occurs. Finally, the ColumnText.Go() method is called. This actually commits the contents of the ColumnText to the document, and also returns a value to the variable status. It returns either NO_MORE_TEXT, which is 1, and/or NO_MORE_COLUMN (2). If NO_MORE_TEXT is returned, everything has been written, otherwise the second column is created and the text added to that. Once ColumnText.HasMoreText returns false, the page is written.

Building on this, if the amount of text spans more than one page, the routine can be rewritten to call Document.NewPage(), and if Go() is called after each Phrase is added to the ColumnText object, it is possible to obtain the current Y position on the page to establish how much room there is left. this enables you to manage widows and orphans - single lines of text that are belong to a paragraph that appear at the end of the preceding page or column (orphans) or appear at the top of a new page or column (widows). It is also possible to pass the parameter "false" into Go(), which does not commit the text to the column, but still allows you to obtain the position as if it was to allow you much finer control over layout.

Related Posts

Previous
Next Post »

Thanks for comments.....