Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
511 views
in Technique[技术] by (71.8m points)

c# - Generate Staff Card

our company wants to print staff card for our personnel so we prepared a template which contains a placeholder for each person's photo, name and department.
we have a database table that includes path to photo, name and department of each person.
I would like to know if there is possibility to loop through that table and add person data into card template and save it.
I'm using C#.Net but if you know a better solution for this reason I'd be glad to listen.

preview of card template

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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:scrapesousersSOU_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..!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...