为什么我尝试打印条码图像时不适合条码打印机设置中指定的纸张尺寸?
Why my bar code image does not fit the specified paper size in bar code printer settings when I try to print it?
我正在使用 Zen 条码渲染框架 在 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();
}
我的主要目标是在出现打印对话框时选择的纸张范围内完整打印条形码及其相关文本。
您可以在下图中查看我的应用程序的 UI:
这是我的打印结果,您会看到它们质量欠佳,而且图像每次都无法正确匹配。我用的是兄弟QL-700
这就是问题所在。打印机的 DPI(每英寸点数)比屏幕高得多。您的屏幕通常具有 96-150 DPI,而大多数打印机的 DPI 为 600 或更高。您正在尝试将以 96 DPI 创建的图像渲染到使用 600+ DPI 进行渲染的设备上。它看起来会像您在图片上显示的那样。
打印机上下文返回的 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);
}
}
}
那么,这在应用程序中的样子是这样的:
此应用还有print-preview。我将 print-preview 缩放到 150% 以显示一切都保持清晰:
我没有打印机。它不是黄色的,所以它拒绝打印(这是为什么?)所以我打印成 PDF。这是放大300%的PDF:
如您所见,条码在打印到 600 DPI 设备时以及在该设备上放大 300% 时都保持清晰。
请记住,Whosebug 在显示图像时会缩放图像,因此它们可能看起来很模糊。单击图像以原始比例查看它。
如果您有任何问题,请告诉我。
我正在使用 Zen 条码渲染框架 在 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();
}
我的主要目标是在出现打印对话框时选择的纸张范围内完整打印条形码及其相关文本。
您可以在下图中查看我的应用程序的 UI:
这是我的打印结果,您会看到它们质量欠佳,而且图像每次都无法正确匹配。我用的是兄弟QL-700
这就是问题所在。打印机的 DPI(每英寸点数)比屏幕高得多。您的屏幕通常具有 96-150 DPI,而大多数打印机的 DPI 为 600 或更高。您正在尝试将以 96 DPI 创建的图像渲染到使用 600+ DPI 进行渲染的设备上。它看起来会像您在图片上显示的那样。
打印机上下文返回的 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);
}
}
}
那么,这在应用程序中的样子是这样的:
此应用还有print-preview。我将 print-preview 缩放到 150% 以显示一切都保持清晰:
我没有打印机。它不是黄色的,所以它拒绝打印(这是为什么?)所以我打印成 PDF。这是放大300%的PDF:
如您所见,条码在打印到 600 DPI 设备时以及在该设备上放大 300% 时都保持清晰。
请记住,Whosebug 在显示图像时会缩放图像,因此它们可能看起来很模糊。单击图像以原始比例查看它。
如果您有任何问题,请告诉我。