Saturday, November 26, 2011

Getting Started with iTextSharp


For the ASP.NET developers out there, if you need to generate PDF reports from your code, there is an open source library called iText# (iTextSharp) that is worth checking out. iTextSharp is a port of the Java iText library written entirely in C#. Source and binaries are available at http://sourceforge.net/projects/itextsharp/.

From what I’ve seen, it works well and only requires one .dll to be copied to your bin directory. Unfortunately, there is no documentation with the product, so I’ll share some of the code I used for a proof of concept that should hopefully get you started.

Using Visual Studio 2005 or greater, or your favorite text editor, create a page with a label called Label1 and a button called Button1. You can skip the label if you want, as I just used it to dump exception output, but I do have it referenced in code. The example will work with any of the Express (free) versions of Visual Studio as well.

First of all, ensure your page has references to ITextSharp.text, ITextSharp.text.PDF, System.IO, and System.Text.

In Button1’s Click event handler, add the following code. My comments appear within square brackets inside the code:

Dim doc As New iTextSharp.text.Document(PageSize.LETTER, 10, 10, 10, 10)

[Here is where you declare the page size and margins.]

Dim output As New MemoryStream()

[You can generate the output directly to a file, but, for demonstration purposes, I just used a MemoryStream object. Note that if you generate your output to a file, you will require write permission on the server in the directory where you want to place your PDF files, otherwise you will get a SecurityException.]

Dim logo As iTextSharp.text.Image
Dim bTest As Boolean
Dim par As Paragraph
Dim tbl As PdfPTable
Dim widths As Single() = {1.3, 1.3}
Dim bfHelvetica As BaseFont = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, False)

[I found the choices of fonts quite limiting, in contrast to the FPDF library I’ve used in PHP at www.whahof.com.]

Dim cb As PdfContentByte
Dim titleFont As iTextSharp.text.Font = New Font(bfHelvetica, 14, Font.BOLD, iTextSharp.text.BaseColor.BLACK)
Dim bodyFont As iTextSharp.text.Font = New Font(bfHelvetica, 10, Font.NORMAL, iTextSharp.text.BaseColor.BLACK)
Dim smallFont As iTextSharp.text.Font = New Font(bfHelvetica, 8, Font.NORMAL, iTextSharp.text.BaseColor.BLACK)

Try
    Label1.Text = String.Empty
    Dim instance As PdfWriter = PdfWriter.GetInstance(doc, output)
    Dim ev As New itsEvents
    instance.PageEvent = ev
    doc.Open()
    cb = instance.DirectContent

    doc.AddAuthor("Curtis Walker")
    doc.AddTitle("This is a test PDF")

[In your PDF, these values will appear under Document Properties. It’s optional, but if you want to add a professional touch, it’s a good idea.]

     par = New Paragraph("Test paragraph", titleFont)
     par.Alignment = 1 ' 1 is center, 0 is left, 2 is right
     doc.Add(par)

     par = New Paragraph(" ", smallFont)
     doc.Add(par)

      tbl = New PdfPTable(2) ' number of columns
      tbl.WidthPercentage = 30
      tbl.HorizontalAlignment = 1
      tbl.DefaultCell.BorderWidthTop = 1
      tbl.DefaultCell.BorderWidthLeft = 1
      tbl.DefaultCell.BorderWidthRight = 1
      tbl.DefaultCell.BorderWidthBottom = 0

[There is a “border” attribute, but I found that it just sets the top value, not all four values above.]

       tbl.SpacingAfter = 0
       tbl.SpacingBefore = 0
       tbl.SetWidths(widths)
       tbl.AddCell(New Phrase("test", bodyFont))
       tbl.AddCell(New Phrase("test2", bodyFont))
       tbl.AddCell(New Phrase("test3", bodyFont))
       tbl.AddCell(New Phrase("test4", bodyFont))
       tbl.AddCell(New Phrase("test5", bodyFont))
       tbl.AddCell(New Phrase("test6", bodyFont))
       tbl.AddCell(New Phrase("test7", bodyFont))
       tbl.AddCell(New Phrase("test8", bodyFont))

       doc.Add(tbl)

       logo = iTextSharp.text.Image.GetInstance(Server.MapPath("~/images/thrashers.jpg"))

[You can pick any image on your server.]

       logo.SetAbsolutePosition(100, doc.PageSize.Height - 100)

[Strangely, the second value is distance from the bottom of the page, not the top. Setting the value to “0” puts it at the bottom.]

        logo.ScaleAbsolute(100, 100)
        bTest = doc.Add(logo)

        doc.NewPage()

        par = New Paragraph("test item on second page", titleFont)
        doc.Add(par)

        doc.Close()

         Response.ContentType = "application/pdf"
         Response.AddHeader("Content-Disposition", "Output.pdf")
         Response.BinaryWrite(output.ToArray())

  Catch ex As Exception
     Label1.Text = ex.Message
  End Try

After the page class, insert the following class that handles the page header and footer events.

Public Class itsEvents
        Inherits PdfPageEventHelper

        Private bfHelvetica As BaseFont = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, False)
        Private smallFont As iTextSharp.text.Font = New Font(bfHelvetica, 8, Font.NORMAL, iTextSharp.text.BaseColor.BLACK)

        Public Overrides Sub OnStartPage(ByVal writer As iTextSharp.text.pdf.PdfWriter, ByVal document As iTextSharp.text.Document)
            Dim cb As PdfContentByte

            cb = writer.DirectContent

            cb.BeginText()
            cb.SetFontAndSize(bfHelvetica, 8)
            cb.SetTextMatrix(30, document.PageSize.Height - 30)
            cb.ShowText("Test header on page " + writer.PageNumber.ToString)
            cb.EndText()

            cb.MoveTo(30, document.PageSize.Height - 35)
            cb.LineTo(document.PageSize.Width - 40, document.PageSize.Height - 35)
            CB.Stroke()
        End Sub

        Public Overrides Sub OnEndPage(ByVal writer As iTextSharp.text.pdf.PdfWriter, ByVal document As iTextSharp.text.Document)
            Dim cb As PdfContentByte

            cb = writer.DirectContent

            cb.BeginText()
            cb.SetFontAndSize(bfHelvetica, 8)
            cb.SetTextMatrix(30, 30)
            cb.ShowText("Test footer on page " + writer.PageNumber.ToString)
            cb.EndText()

            cb.MoveTo(30, 40)
            cb.LineTo(document.PageSize.Width - 40, 40)
            cb.Stroke()
        End Sub
    End Class

You should be set to build your project and run the page. Click the button and you should get a PDF file coming up in your browser. Once I found the code, I found that it went pretty smoothly.

If you want to deploy the isharptext.dll and your code to a host on a shared plan, you may run into trouble. The pre-built .dll is strongly typed and though your code may have worked locally, you may get an error message about not allowing partially trusted callers.

After doing a little research, I found that all you have to do is recompile the source using Visual Studio 2005 and adding the following lines to assembly.cs:

using System.Security;
[assembly:AllowPartiallyTrustedCallers]

Using this rebuilt .dll, everything worked on my hosting provider just as it did locally under both IIS and the lightweight development Web Server provided with the .NET SDK that is most often installed with Visual Studio. For my example, click here.

I’ve just scratched the surface and there’s a lot more to do with this library, but this code should get you started in generating PDF files from your .NET application or Web site.

Sunday, November 13, 2011

This Moment in Winnipeg Hockey History - The Day After Armageddon

It was April 28, 1996 and the Winnipeg Jets were shaking hands with the Detroit Red Wings after being eliminated in the first round of the Stanley Cup playoffs. The next time the Jets would take to the ice was at the America West Arena as the Phoenix Coyotes. The unthinkable was now reality.

Hockey Armageddon had come to Winnipeg.

Despite claims to the contrary, however, the sun did come up the next morning.

Winnipeg hockey fans would now be in for a new experience. The International Hockey League was in town.

Months earlier, the Shindleman brothers purchased a conditional interest in the Peoria Rivermen with the intention of moving them to Winnipeg, but then a group led by Jeff Thompson and former Jet Thomas Steen purchased a conditional interest in the Minnesota Moose and wanted to move that team to Winnipeg. Faced with competing bids, the IHL Board of Governors, in a move that would profoundly and negatively impact the long-term interests of hockey in Winnipeg, awarded relocation rights to the Minnesota Moose.

The Moose were in their second season in the Twin Cities, having started as an expansion team to fill the void of jilted fans who had recently seen the Minnesota North Stars to move to Dallas. They were about to pack up shop and attempt to fill the same void for Winnipeg fans.

The Moose played out of the St. Paul Civic Center and then the Target Center, taking up dates that were originally reserved for the Jets, who were a whisker away from moving there a year earlier. During their brief life span, the Moose failed to capture much in the way of fan support and though they made the playoffs in their first season, they were bottom-feeders in their second and final season and few were left at the end to notice the moving vans headed north.

Former Jet Dave Christian, one of the fixtures in the Moose lineup, was asked by the Minneapolis Star-Tribune during the 1995-1996 season if he wanted to make the playoffs. He said “No.” When asked why, he responded, “Ownership.”

Upon the completion of some difficult negotiations with Winnipeg Enterprises on a lease for the Winnipeg Arena, the Moose arrived in Winnipeg and were rechristened the “Manitoba Moose”. The “Thompson Group” as the ownership was then known, soon gave way to Mark Chipman, a last-minute addition to the group who would soon assert full control of every facet of the franchise. Minnesota Moose coach Frank Serratore was replaced with Jean Perron, a man with substantial NHL credentials and a Stanley Cup championship to his credit. Randy Carlyle, an assistant coach with the Jets and former Jets player, was brought in to assist Perron.

On the ice, the roster was completely remade. Former Jets players Randy Gilhen, Scott Arniel, and Russ Romaniuk were brought in among many others to supplement holdovers Stephane Morin, Jim Paek, and Andy “Schnooky” Schneider.

My first encounter with this new franchise was a package in the mail containing nothing more than a brochure and a bill. After failing to respond to this invoice, I got a call from a fast-talking salesman from the Moose trying to convince me that the mini-pack seat I had for the Jets’ last season was about to be taken by a prospective season ticket holder, but that I had the right of first refusal.

I’m not saying I’ve never been taken for a ride before, but I’m not that gullible. I called his bluff and let him sell this seat to someone else. Not that I really needed confirmation, but just out of curiosity, before the opening game, I asked at the ticket window if the seat was available. Sure enough, it was.

The Moose’s first home game took place on the night of October 11, 1996 and I was there to see them take on the Las Vegas Thunder at the reconfigured Arena. The upper decks were closed, the north end ice level section was turned into a club lounge, and a number of sections behind the north end goal were replaced by new purple club seating. I wasn’t the only one to ask, “Why didn’t they do this for the Jets?”

Skating out from underneath a pair of inflatable antlers, the Moose, sporting new uniforms that looked like they had been borrowed from the Mighty Ducks of Anaheim, made their inaugural appearance at their new home. Not unexpectedly, they laid an egg that night and were shut out by Parris Duffus, who was property of the relocated Jets’ franchise.

Yes, I was there at Opening Night. In this case, however, I think history will show that virtually none of the attendees would be willing to admit that they were there.

The Moose did, however, make an indelible first impression. Fights were not in short supply, and from that night on, I would always refer to them as the “Fighting Moose”. Greg Pankewicz, one the stars on that first Moose team, showed his colors as one of the most colorful players to ever lace on a pair of skates. He would rack up more than 200 penalty minutes that year, and a good deal of those came in ten-minute increments. When the Arena was demolished a decade later, the much-abused door to the penalty box should have been rescued and bronzed for “Captain Misconduct”.

The promotions were just as colorful as some of the players. There was the forgettable “sing for your supper” promotion where candidates belted out some words and the fans voted with their applause on the winner. Between periods was “Turkey Curling” where contestants would hurl frozen poultry carcasses down the ice.

My eyebrows were raised when I saw Chipman running up and down the stands while games were going on. Having been a Jets’ season ticket holder for five seasons and attended countless number of games over the years, I could count on the fingers of one hand the number of times I ever saw Jets’ President Barry Shenkarow, even on television. Hands-on ownership had come to Winnipeg in full force and, regrettably, it hasn’t left.

The Moose drew some decent crowds that first season, but losses piled up as fast as the fight card. The most entertaining part of some of those games was listening to Jean Perron’s post-game comments on the way home. In his broken English, I remember him saying, “When tree player go to da puck carrier, what can I do?”

Late in the season, with the team floundering, Chipman fired Perron less than one year into his three-year deal, and installed Carlyle as his replacement. The team responded better to the man who would become Chipman’s favorite crony, but it was far too late to salvage anything from what had been a lost season.

There were 19 teams in the IHL in 1996-1997 and, in a system even more inclusive than the NHL, something I never thought possible, only three missed the playoffs. The Moose were one of them. The Moose’s inaugural season in Winnipeg could be filed under the headline of “you only get one chance to make a good first impression”.

Things would go downhill from there, but that year set the stage for an appreciation of hockey at the grassroots level that I could never have imagined. For those of you that think Slap Shot is a piece of unrealistic fiction, it’s a lot closer to a documentary than people would like to believe.

Put on the foil, here come the Moose.

Friday, November 4, 2011

The New Airport Terminal

Like many others in the capital of the Socialist People’s Republic of Manitoba, I was curious enough to go check out the new airport terminal that recently opened. I’ve never travelled by air before, nor do I have any desire to do so, but I’ve enjoyed watching the planes from the observation lounge, which I’ve noticed to be a popular attraction.

Upon your arrival along Wellington Avenue, you can now drive right up to the second level for departures, or stick to the first level for the arrivals floor.



Once you pass by the new terminal, there’s no stopping in front of the old terminal, and security personnel will simply wave you through. At left is the new indoor parkade. Thrifty Winnipeggers need not fear, however, as the outdoor Economy lot is still available.



The second level.

I walked through the parkade with one of the Gold Wing Ambassadors who looked to be just as lost as I was in trying to make my way though the concrete jungle to the new building.


The ground floor. Notice above is the walkway from the parkade, which is only partially covered. Most of the walk from the terminal to the parkade will leave you exposed to the wrath of Old Man Winter, a little detail that is sure to be noticed by travellers.

Once inside, the new terminal is certainly more spacious, as advertised. Natural light is in abundance, which is nice.



The luggage carousels on the first floor.



As you’d expect, escalators and a staircase, much like the old terminal.


The departure check-in lines. No shortage of counters and you can see from the aesthetics that the building looks a lot less utilitarian than its predecessor.

The terminal, however, is still a work in progress. There are still many signs of construction inside and outside and even the washroom I used looked unfinished. A soap container was lying out on the table and there were no paper towels to be found.

I walked around like a tourist, checking out the new sights, but, sadly, unlike the old terminal, there really isn’t much to see unless you’re actually flying somewhere. Most of the terminal is only accessible to travellers who have gone through security and, to my shock, there did not appear to be an observation lounge. I asked at the information desk and got the answer I didn’t want to hear. I was told they were planning to put some chairs and tables by a window near where Stella’s restaurant is being built, but other than that, the observation lounge is now a thing of the past. For all the time and effort they put into designing this terminal, that was a major gaffe that I can only hope will be rectified at some point down the road.

I can’t vouch for the post-security areas, but I suspect that, just with the increase in space alone, that the air traveller’s experience can’t help but be improved. There were, however, some serious design omissions that I hope aren’t repeated in the rest of the terminal.