Generate Staff Card

This is no problem at all using C# and GDI+

Here is the short version:

  1. Create a Bitmap of the right size and resolution
  2. Measure the coordinates of the images and text you want to have on it
  3. Pull the data from your database
  4. Use Graphics.DrawImage and Graphics.DrawString to create the graphics
  5. Save in a format you like, preferably PNG as this will keep the text sharp

Here come the details:

  1. You need to calculate how many pixels your image should have. Since you want to be able to print it you should use at least 150dpi or 200dpi.

The Image you posted has no DPI setting and 1004x638 pixels; setting it to 150dpi results in a physical size of 170x108 mm. Let's assume that this is OK..

So we create a bitmap with these parameters:

Size keyCardSize = new Size (1004, 638);
float Dpi = 150f;
Bitmap bmp = new Bitmap(keyCardSize.Width, keyCardSize.Height);
bmp.SetResolution(Dpi, Dpi);
  1. The code below will use millimeters as the unit. You may want to change this to something else.

Looking at your template we see 6 images (logo, photo and 4 icons) and 7 chunks of text (name, position, dept. and four contact texts).

The basic commands for drawing an image or a text with a Graphics G look like this:

   G.DrawImage(bitmap, location);
   G.DrawString(text, font, brush, location);

In our case this works fine for the logo and the photo since they are left aligned. All you need to do is to measure the positions and create the location points. Make sure you either create the images in the correct size&resolution or that you adapt the dpi to make up for differing pixel sizes!

Update: I have included code to adapt the photo's dpi to make the width fit in the 30mm frame in the template. This assumes that the proportions are correct and/or that we care more about the width than the height.. If we need to match both, either get the proportions right or ask for a cropping code ;-)

Measuring the rest of our items is a little more complicated, since they all are right aligned. Here is an example how to do it for a string txt1:

SizeF s1 = G.MeasureString(txt1, font1, PointF.Empty, StringFormat.GenericTypographic);
G.DrawString(txt1, font1, brush1, new Point((int)(rightBorder - s1.Width), y1));

You can (and must) measure the top (Y) of each location but the left (X) must be calculated like above!

Note that you need to tell the measurement command the font you want to use; ignore the other params! After measuring the right border these commands will work fine with the necessary data and graphics objects..

  1. Pulling the data from your database. I assume you can do that! I further assume that you can change & expand the code below to fill the data fields and make filename dynamic with your records..

4&5. See this code example:


 private void Button_Click(object sender, EventArgs e)
 {
    string FontFamily = "Verdana";

    string fileName = "d:\\template.png";

    Size keyCardSize = new Size (1004, 638); // 170x108mm
    float Dpi = 150f;
    Bitmap bmp = new Bitmap(keyCardSize.Width, keyCardSize.Height);
    bmp.SetResolution(Dpi, Dpi);

    // test data:
    Bitmap photo = new Bitmap(@"D:\scrape\sousers\SOU_JonSkeet.jpeg");
    // I have measured the photo should be 30mm wide
    // so with 25.4mm to the inch we calculate a fitting dpi for it:  
    float photoDpi = photo.Width * 25.4f / 30f;
    photo.SetResolution(photoDpi , photoDpi );

    Font font1 = new Font(FontFamily, 23f);
    Font font2 = new Font(FontFamily, 12f);
    Font font3 = new Font(FontFamily, 14f);

    using (Graphics G = Graphics.FromImage(bmp))
    using (SolidBrush brush1 = new SolidBrush(Color.MediumVioletRed))
    using (SolidBrush brush2 = new SolidBrush(Color.Gray))
    {
        G.Clear(Color.White);
        G.InterpolationMode = InterpolationMode.HighQualityBicubic;
        G.PageUnit = GraphicsUnit.Millimeter;
        G.SmoothingMode = SmoothingMode.HighQuality;

        StringFormat sf = StringFormat.GenericTypographic;

        int lBorder= 10;
        int rBorder= 160;
        int y1 = 10;
        int y2 = 25;
        //..
        int y4 = 60;
        //..
        //G.DrawImage(logo, imgLoc1);
        G.DrawImage(photo, new Point(lBorder, y4));
        //G.DrawImage(img3, imgLoc3);
        //G.DrawImage(img4, imgLoc4);
        //G.DrawImage(img5, imgLoc5);


       // test data:
        string txt1 = "Jon Skeet";
        string txt2 = "C Sharp Evangelist";
        //..

        SizeF s1 = G.MeasureString(txt1, font1, PointF.Empty, sf);
        SizeF s2 = G.MeasureString(txt2, font2, PointF.Empty, sf);
        //..

        G.DrawString(txt1, font1, brush1, new Point((int)(rBorder- s1.Width), y1));
        G.DrawString(txt2, font2, brush2, new Point((int)(rBorder- s2.Width), y2));

        //G.DrawString(txt3, font2, brush2, txtLoc3);
        //..
        //G.DrawString(txt7, font3, brush2, txtLoc7);

        G.FillRectangle(brush1, new RectangleF(rBorder - 1.5f, 52f, 1.5f, 46f));

  }

  bmp.Save(fileName, ImageFormat.Png);

  font1.Dispose();
  font2.Dispose();
  font3.Dispose();

  photo.Dispose();
  //..
}

I hope this gets you going. If you have questions, feel free to ask..

Here is the rudimentary result:

enter image description here

An afterthought: You may want to simplify the whole code by using the template as the start: You can have the logo, the icons and the vertical bar all in place and only need to draw one image and the texts..!


Okay, just an idea may not work, but I thought I would throw something out there to maybe help!

How about you create a program that does as you say , loops the database. But for the Staff cards create a User interface with like a GraphicsBox, and a few text boxes; Create/use a print function on the Ui, make the window borderless for the printout.

Im not sure if this would work as i use C++ and never really thought of doing something like this but i got this from the top of my head give it ago you never know!

But then you would obviously be printing to a high quality plastic i assume, or is it getting laminated? Not that is really matters just interested :)