Why my bar code image does not fit the specified paper size in bar code printer settings when I try to print it?

半腔热情 提交于 2020-08-10 22:50:43

问题


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:

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


回答1:


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:

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

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%:

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.



来源:https://stackoverflow.com/questions/63246342/why-my-bar-code-image-does-not-fit-the-specified-paper-size-in-bar-code-printer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!