Почему мое изображение штрих-кода не соответствует размеру бумаги, указанному в настройках принтера штрих-кода, когда я пытаюсь его распечатать? - PullRequest
0 голосов
/ 04 августа 2020

Я использую Zen Barcode Rendering Framework для создания штрих-кодов в приложении формы C# windows. У меня есть два текстовых поля (одно для самого штрих-кода и одно для соответствующего текста, который я хочу напечатать на этикетке штрих-кода). Точно так же я загружаю сгенерированное изображение штрих-кода в графическое поле и пытаюсь распечатать его, но каждый раз, когда я нажимаю кнопку печати, результат оказывается неприемлемым (иногда принтер печатает белую пустую этикетку, а иногда штрих-код печатается не полностью. Интересно, что я должен сказать, что для того, чтобы штрих-код отображался на этикетке, даже если он кажется неполным, мне нужно выбирать очень большие размеры бумаги). Вот мой код:

Код для события нажатия кнопки генерации штрих-кода:

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;

}

Код для события нажатия кнопки печати:

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();
    }
}

И мой Функция Doc_PrintPage ():

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();
}

Моя основная цель - полностью напечатать штрих-код с соответствующим текстом внутри границ бумаги, который выбирается при появлении диалогового окна печати. ​​

Вы можете просмотреть мои пользовательский интерфейс приложения на изображении ниже: 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 введите описание изображения здесь

1 Ответ

4 голосов
/ 08 августа 2020

Так вот в чем проблема. У принтеров DPI (точек на дюйм) намного выше, чем у вашего экрана. Ваш экран обычно имеет 96–150 точек на дюйм, тогда как большинство принтеров имеют разрешение 600 точек на дюйм или выше. Вы пытаетесь визуализировать изображение, созданное с разрешением 96 точек на дюйм, на устройстве, которое использует для визуализации более 600 точек на дюйм. Он будет выглядеть примерно так, как то, что вы показываете на своих изображениях.

Объект Graphics, возвращаемый контекстом принтера, будет сильно отличаться от объекта Graphics, созданного для отображения информации на экране. Итак, что вам нужно сделать, так это отрендерить объект Graphics, а не Image, который вы создали для отображения на экране.

Итак, мы собираемся изменить ваш код:

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);
        }
    }
}

Итак, в приложении это выглядит так:

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 печать

Как видите, штрих-код остается четким и чистым при печати на устройстве с разрешением 600 точек на дюйм, а также при увеличении на этом устройстве 300%.

Помните, что StackOverflow масштабирует изображения при их отображении, поэтому они могут выглядеть размытыми. Нажмите на изображение, чтобы увидеть его в исходном масштабе.

Если у вас есть вопросы, дайте мне знать.

...