0

I am using Zen Barcode Rendering Framework to create bar codes in C# windows form application. I have two text boxes (one for bar code itself and one for the relevant text that I want it to be printed on the bar code label). Similarly, I am loading the generated bar code image to a picture box and try to print that but every time I press the print button, the result is inappropriate (Sometimes the printer prints a white empty label and sometimes the bar code gets printed incomplete. Interestingly, I have to say that in order to make the bar code appear on the label even if it appears incomplete, I have to choose very large paper sizes). Here's my code:

The code for my generate bar code button's click event:

private void Button1_Click(object sender, EventArgs e)
{
        string barcode = textBox1.Text;

        Zen.Barcode.Code128BarcodeDraw brcd = Zen.Barcode.BarcodeDrawFactory.Code128WithChecksum;
        var barcodeImage = brcd.Draw(barcode, 50);

        int resultImageWidth;
        if(barcodeImage.Width >= textBox2.Text.Length*8)
        {
            resultImageWidth = barcodeImage.Width;
        }
        else
        {
            resultImageWidth = textBox2.Text.Length*8;
        }

        var resultImage = new Bitmap(resultImageWidth, barcodeImage.Height + 60); // 20 is bottom padding, adjust to your text

        using (var graphics = Graphics.FromImage(resultImage))
        using (var font = new Font("IranYekan", 10))
        using (var brush = new SolidBrush(Color.Black))
        using (var format = new StringFormat()
        {
            Alignment = StringAlignment.Center, // Also, horizontally centered text, as in your example of the expected output
            LineAlignment = StringAlignment.Far
        })
        {
            graphics.Clear(Color.White);
            graphics.DrawImage(barcodeImage, (resultImageWidth - barcodeImage.Width)/2, 0);
            graphics.DrawString(textBox1.Text, font, brush, resultImage.Width / 2, resultImage.Height-30, format);
            graphics.DrawString(textBox2.Text, font, brush, resultImage.Width / 2, resultImage.Height, format);
        }

        pictureBox1.Image = resultImage;

}

The code for my print button's click event:

private void Button2_Click(object sender, EventArgs e)
{
    PrintDialog pd = new PrintDialog();
    PrintDocument doc = new PrintDocument();
    doc.PrintPage += Doc_PrintPage;
    pd.Document = doc;
    if (pd.ShowDialog() == DialogResult.OK)
    {
        doc.Print();
    }
}

And my Doc_PrintPage() function:

private void Doc_PrintPage(object sender, PrintPageEventArgs e)
{
    Bitmap bm = new Bitmap(pictureBox1.Width, pictureBox1.Height);
    pictureBox1.DrawToBitmap(bm, new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height));
    e.Graphics.DrawImage(bm, 0, 0);
    bm.Dispose();
}

My main goal is to print the bar code completely with its relevant text inside the paper bounds that gets selected when print dialog appears.

You can view my application's UI in the image below: enter image description here

Here are my printed results as you see they lack quality and the image does not fit correctly every time. I use Brother QL-700 enter image description here enter image description here enter image description here enter image description here

Naser.Sadeghi
  • 1,341
  • 1
  • 12
  • 35
  • Make sure you have the vendors latest driver installed. Are you connecting to the printer IP or using the print driver? You should always use the print driver which initializes the printer and configured the options. – jdweng Aug 04 '20 at 12:06
  • @jdweng As I have installed the print driver, I just select my printer from the list of available printers and after setting the appropriate paper size I click OK on the print dialog. – Naser.Sadeghi Aug 04 '20 at 12:15
  • Does driver have option to FIT Paper size. I would create a panel and then picture box and text into the panel and print the panel. – jdweng Aug 04 '20 at 12:19
  • As far as I know, no it does not. – Naser.Sadeghi Aug 04 '20 at 12:20
  • See following : https://stackoverflow.com/questions/45743005/resize-panel-to-print-full-page/45787892 – jdweng Aug 04 '20 at 12:24
  • You may need to scale your image down to the size (in pixels) of the print document page. I believe you'd do this by applying a graphics transform to `e.Graphics`. – Ann L. Aug 04 '20 at 12:53
  • @AnnL. It didn't work unfortunately. Isn't there a way to force the pictureBox image print in the scale of selected paper size? – Naser.Sadeghi Aug 08 '20 at 15:37
  • I just updated the question in order to show the printed results that I get. – Naser.Sadeghi Aug 08 '20 at 15:41
  • Crucial to a sharp barcode on paper is that it doesn't get resized. Right now get gets resized *twice*. First to force it to fit the picturebox, scaling down. Next to match the printer resolution, scaling back up. Edit the PrintPage event handler to e.Graphics.DrawImage(pictureBox1.Image, 0, 0) for a very quick improvement. How to get Code128BarcodeDraw to generate an image with the native printer resolution is not obvious, the bigger you make it the better it will look. – Hans Passant Aug 08 '20 at 17:53
  • printer DPI is quite different than Screen DPI. A screen typically is at 96 to 150 DPI whereas a printer is at 300-1200+ DPI. – Andy Aug 08 '20 at 18:02
  • If you are using a Brother QL-700, keep in mind that you should not be creating a barcode in the Zen Framework and sending that as an image to the printer. Have you tried to use the P-touch Editor to send your barcodes to the printer? – Brian Anderson Aug 10 '20 at 14:36
  • Also, make sure the label is coming out of the printer one barcode character at a time and you are not printing the barcode vertically. In other words, the barcode should read in the direction that it is printed. (Heve you tried to print a rotated barcode). Also, make sure there is no compression done to the image. – Brian Anderson Aug 10 '20 at 14:57

1 Answers1

5

So this is the issue. Printers have a DPI (Dots Per Inch) that is much, much higher than your screen. Your screen will typically have 96-150 DPI, whereas most printers will be 600 DPI or higher. You are trying to render an image that was created at 96 DPI on to a device which uses 600+ DPI to render. It's going to look, well, like what you are showing on your images.

The Graphics object returned by a printer context is going to be very different than the Graphics object that is created for displaying information on a screen. So, what you need to do is render to the Graphics object, not to an Image that you created for screen display.

So we are going to rearrange your code:

private void BtnScreen_Click(object sender, EventArgs e)
{
    // if there was a previous image in the picture box, dispose of it now
    PicCode.Image?.Dispose();

    // create a 24 bit image that is the size of your picture box
    var img = new Bitmap(PicCode.Width, PicCode.Height, PixelFormat.Format24bppRgb);
    // wrap it in a graphics object
    using(var g = Graphics.FromImage(img))
    {
        // send that graphics object to the rendering code
        RenderBarcodeInfoToGraphics(g, TxtCode.Text, TxtInfo.Text,
            new Rectangle(0, 0, PicCode.Width, PicCode.Height));
    }

    // set the new image in the picture box
    PicCode.Image = img;
}

private void BtnPrinter_Click(object sender, EventArgs e)
{
    // create a document that will call the same rendering code but
    // this time pass the graphics object the system created for that device
    var doc = new PrintDocument();
    doc.PrintPage += (s, printArgs) =>
    {
        // send that graphics object to the rendering code using the size
        // of the media defined in the print arguments
        RenderBarcodeInfoToGraphics(printArgs.Graphics, TxtCode.Text,
            TxtInfo.Text, printArgs.PageBounds);
    };

    // save yourself some paper and render to a print-preview first
    using (var printPrvDlg = new PrintPreviewDialog { Document = doc })
    {
        printPrvDlg.ShowDialog();
    }

    // finally show the print dialog so the user can select a printer
    // and a paper size (along with other miscellaneous settings)
    using (var pd = new PrintDialog { Document = doc })
    {
        if (pd.ShowDialog() == DialogResult.OK) { doc.Print(); }
    }
}

/// <summary>
/// This method will draw the contents of the barcode parameters to any
/// graphics object you pass in.
/// </summary>
/// <param name="g">The graphics object to render to</param>
/// <param name="code">The barcode value</param>
/// <param name="info">The information to place under the bar code</param>
/// <param name="rect">The rectangle in which the design is bound to</param>
private static void RenderBarcodeInfoToGraphics(
    Graphics g, string code, string info, Rectangle rect)
{
    // Constants to make numbers a little less magical
    const int barcodeHeight = 50;
    const int marginTop = 20;
    const string codeFontFamilyName = "Courier New";
    const int codeFontEmSize = 10;
    const int marginCodeFromCode = 10;
    const string infoFontFamilyName = "Arial";
    const int infoFontEmSize = 12;
    const int marginInfoFromCode = 10;

    // white background
    g.Clear(Color.White);

    // We want to make sure that when it draws, the renderer doesn't compensate
    // for images scaling larger by blurring the image. This will leave your
    // bars crisp and clean no matter how high the DPI is
    g.InterpolationMode = InterpolationMode.NearestNeighbor;

    // generate barcode
    using (var img = BarcodeDrawFactory.Code128WithChecksum.Draw(code, barcodeHeight))
    {
        // daw the barcode image
        g.DrawImage(img,
            new Point(rect.X + (rect.Width / 2 - img.Width / 2), rect.Y + marginTop));
    }

    // now draw the code under the bar code
    using(var br = new SolidBrush(Color.Black))
    {
        // calculate starting position of text from the top
        var yPos = rect.Y + marginTop + barcodeHeight + marginCodeFromCode;

        // align text to top center of area
        var sf = new StringFormat
        {
            Alignment = StringAlignment.Center,
            LineAlignment = StringAlignment.Near
        };

        // draw the code, saving the height of the code text
        var codeTextHeight = 0;
        using (var font =
            new Font(codeFontFamilyName, codeFontEmSize, FontStyle.Regular))
        {
            codeTextHeight = (int)Math.Round(g.MeasureString(code, font).Height);

            g.DrawString(code, font, br,
                new Rectangle(rect.X, yPos, rect.Width, 0), sf);
        }

        // draw the info below the code
        using (var font =
            new Font(infoFontFamilyName, infoFontEmSize, FontStyle.Regular))
        {
            g.DrawString(info, font, br,
                new Rectangle(rect.X,
                    yPos + codeTextHeight + marginInfoFromCode, rect.Width, 0), sf);
        }
    }
}

So, what this looks like in the app is this:

app

This application also has print-preview. I scaled the print-preview to 150% to show that everything is staying crisp:

print preview

I don't have a printer. It's out of Yellow, so it refuses to print (why is that?) so instead I printed to PDF. This is that PDF scaled up 300%:

pdf print

As you can see, the barcode stays crisp and clean when printing to a 600 DPI device and also when you zoom in on that device 300%.

Please keep in mind that StackOverflow scales images when displaying them, so they may look blurry. Click on the image to see it in it's original scale.

If you have any questions, please let me know.

Andy
  • 12,859
  • 5
  • 41
  • 56
  • 1
    Thanks for you detailed answer Andy. You completely deserved the 50 reputation. If I face any issues I'll try to contact you again. – Naser.Sadeghi Aug 10 '20 at 21:11
  • 1
    @Naser.Sadeghi -- You are very welcome! Hopefully all goes well for you. I'm always around if you run in to any bumps. Good luck! – Andy Aug 10 '20 at 23:16
  • I still have trouble printing this bar code unfortunately. The quality issue has been solved but I am still unable to print the whole picture in any given paper size when I tried to manually set the width and height it didn't work instead I list the whole available sizes of a printer and select one. And the result is still not correct. – Naser.Sadeghi Aug 15 '20 at 16:14
  • When I print to pdf it's OK but in real printer I still have problems. – Naser.Sadeghi Aug 15 '20 at 16:15
  • @Naser.Sadeghi -- you will probably have to change the size of your barcode. Instead of using `50`, try using `30`... also adjust the Em size of your fonts. – Andy Aug 16 '20 at 03:56