C# 印表機(PrintDocument的解析度 設定) ~ 像素(Pixels)/英吋(Inches)/毫米(Millimeters) 轉換函數

C# 印表機(PrintDocument的解析度 設定) ~ 像素(Pixels)/英吋(Inches)/毫米(Millimeters) 轉換函數

C# 印表機(PrintDocument的解析度 設定) ~  像素(Pixels)/英吋(Inches)/毫米(Millimeters) 轉換函數


資料來源:

https://blog.csdn.net/wangnaisheng/article/details/139059374
https://learn.microsoft.com/zh-tw/dotnet/api/system.drawing.graphicsunit?view=windowsdesktop-9.0&viewFallbackFrom=dotnet-plat-ext-8.0
https://radio-idea.blogspot.com/2016/09/c-printdocument.html#google_vignette


GITHUB: https://github.com/jash-git/CS_PrintDocument_ThermalPrinter


01.相關實驗取得參數規則備份

C# PrintDocument 文字大小 -> 圖形實際量測大小 紀錄

e.Graphics.PageUnit = GraphicsUnit.Pixel;
"Arial", 12, FontStyle.Bold -> Width = Height = 4mm
"Arial", 10                 -> Width = Height = 3nm
y+=X			    -> Height(X) = 字高+1 (mm)


02.Code:(三台熱敏印表機測試 確定印出來的圖片/文字大小都是可控且一致)

using System;
using System.Drawing;
using System.Drawing.Printing;
using ZXing;
using ZXing.Windows.Compatibility;// NET5之後CS3050(Error CS0305 Using generic type 'BarcodeWriter ' requires type 1) 解決方法 : https://github.com/micjahn/ZXing.Net/issues/458
using ZXing.Common;
using ZXing.QrCode;
using System.Runtime.Intrinsics.Arm;

class Program
{
    //---
    //DPI 相關函數
    //https://blog.csdn.net/wangnaisheng/article/details/139059374
    public static void GetScreenDpi(out float DpiX, out float DpiY)//系統DPI
    {
        //Dots Per Inch(每英寸點數): 意思是指每一英吋長度中,取樣或可顯示或輸出點的數目
        using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
        {
            DpiX = g.DpiX;
            DpiY = g.DpiY;
        }
    }
    public static float PixelsToInches(int pixels, float dpi)//像素 -> 英吋
    {
        return pixels / dpi;
    }
    public static float PixelsToMillimeters(int pixels, float dpi)//像素 -> 毫米
    {
        float inches = PixelsToInches(pixels, dpi);
        return inches * 25.4f;
    }

    public static int MillimetersToPixels(float millimeters, float dpi)//毫米 -> 像素
    {
        float inches = millimeters / 25.4f;
        return (int)(inches * dpi + 0.5f); // 使用0.5f进行四舍五入处理
    }
    //---DPI 相關函數

    static Bitmap QrCode(String StrData)
    {
        // Create a BarcodeWriter instance
        var barcodeWriter = new BarcodeWriter();//ZXing.Windows.Compatibility
        barcodeWriter.Format = BarcodeFormat.QR_CODE;
        barcodeWriter.Options.Hints.Add(EncodeHintType.CHARACTER_SET, "UTF-8");  //編碼字元utf-8
        barcodeWriter.Options.Hints.Add(EncodeHintType.ERROR_CORRECTION, ZXing.QrCode.Internal.ErrorCorrectionLevel.H); //錯誤校正等級
        barcodeWriter.Options.Height = 300;
        barcodeWriter.Options.Width = 300;
        barcodeWriter.Options.Margin = 0; //外邊距

        // Generate the barcode as a Bitmap
        Bitmap barcodeBitmap = barcodeWriter.Write(StrData);

        // Save the barcode as a BMP file
        barcodeBitmap.Save("qrcode.bmp", System.Drawing.Imaging.ImageFormat.Bmp);

        return barcodeBitmap;
    }
    static Bitmap BarCode(String StrData)
    {
        // Create a BarcodeWriter instance
        var barcodeWriter = new BarcodeWriter();//ZXing.Windows.Compatibility
        barcodeWriter.Format = BarcodeFormat.CODE_128;
        barcodeWriter.Options.Height = 100;
        barcodeWriter.Options.Width = 300;

        // Generate the barcode as a Bitmap
        Bitmap barcodeBitmap = barcodeWriter.Write(StrData);

        // Save the barcode as a BMP file
        barcodeBitmap.Save("barcode.bmp", System.Drawing.Imaging.ImageFormat.Bmp);

        return barcodeBitmap;
    }
    static void Main()
    {
        float SysDpiX, SysDpiY;
        GetScreenDpi(out SysDpiX,out SysDpiY);
        Bitmap bmp1 = QrCode("相關網站: https://github.com/micjahn/ZXing.Net/issues/458");
        Bitmap bmp2 = BarCode("1234567890");
        string targetPrinterName = "POS-80C";//"POS80D";//"80mm Series Printer";//"80mm_TCPMode"; // 替換成你實際的熱感印表機名稱

        PrintDocument printDoc = new PrintDocument();

        // 指定印表機
        bool found = false;
        foreach (string printer in PrinterSettings.InstalledPrinters)
        {
            if (printer.Equals(targetPrinterName, StringComparison.OrdinalIgnoreCase))
            {
                printDoc.PrinterSettings.PrinterName = printer;
                found = true;
                break;
            }
        }

        if (!found)
        {
            Console.WriteLine($"找不到印表機:{targetPrinterName}");
            return;
        }

        // 設定邊界為 0
        printDoc.DefaultPageSettings.Margins = new Margins(0, 0, 0, 0);

        // 加入列印事件
        printDoc.PrintPage += (sender, e) =>
        {
            /*
            //https://learn.microsoft.com/zh-tw/dotnet/api/system.drawing.graphicsunit?view=windowsdesktop-9.0&viewFallbackFrom=dotnet-plat-ext-8.0
            Display	1	
            指定顯示裝置的測量單位。 一般來說,視訊顯示會使用像素,而印表機會使用 1/100 英吋。

            Document	5	
            指定文件單位 (1/300 英吋) 做為測量單位。

            Inch	4	
            指定英吋做為測量單位。

            Millimeter	6	
            指定公釐做為測量單位。

            Pixel	2	
            指定裝置像素做為測量單位。

            Point	3	
            指定印表機的點 (1/72 英吋) 做為測量單位。

            World	0	
            指定全局座標系統的單位做為測量單位。            
            */
            //e.Graphics.PageUnit = GraphicsUnit.Document;//300DPI ~ https://radio-idea.blogspot.com/2016/09/c-printdocument.html#google_vignette
            e.Graphics.PageUnit = GraphicsUnit.Pixel;//解析度 ~ https://radio-idea.blogspot.com/2016/09/c-printdocument.html#google_vignette

            Graphics g = e.Graphics;//抓取印表機畫布
            /*
            Bitmap BitmapBuf = new Bitmap((int)(80 * 3.937),5000);//建立BMP記憶體空間
            Graphics g = Graphics.FromImage(BitmapBuf);//從BMP記憶體自建畫布 ~ https://stackoverflow.com/questions/10868623/converting-print-page-graphics-to-bitmap-c-sharp
            g.Clear(Color.White);//畫布指定底色
            //*/

            Font font = new Font("Arial", 10);
            Brush brush = Brushes.Black;

            int y = 10;

            /*
             熱敏印表機實驗取得數據:
                78mm : 78-3*2(設備邊界) = 72mm
                56mm : 56-3*2(設備邊界) = 50mm
                大小紙張可列印之差: (72-50)=22mm
            */
            g.DrawString("文字致中測試", new Font("Arial", 12, FontStyle.Bold), brush, MillimetersToPixels(((78-12) / 2 - (4*3)), 203), y);//紙張寬度((78-12)/2)-3個字寬(4*3)
            y += MillimetersToPixels(5, 203);//5=字高+1

            g.DrawString("文字致中測試", font, brush, MillimetersToPixels(((78 - 12) / 2 - (3 * 3)), 203), y);//紙張寬度((78-12)/2)-3個字寬(3*3)
            y += MillimetersToPixels(4, 203);//4=字高+1

            // 列印標題
            g.DrawString("收據列印示範", new Font("Arial", 12, FontStyle.Bold), brush, 0, y);
            y += MillimetersToPixels(5, 203);//5=字高+1

            // 繪製文字
            g.DrawString("商品:測試產品", font, brush, 10, y);
            y += MillimetersToPixels(4, 203);//4=字高+1
            g.DrawString("數量:2", font, brush, 10, y);
            y += MillimetersToPixels(4, 203);//4=字高+1
            g.DrawString("總價:NT$200", font, brush, 10, y);
            y += MillimetersToPixels(10, 203);

            // 繪製方形區塊(模擬框)
            Pen pen = new Pen(Color.Black, 1);
            Rectangle rect = new Rectangle(0, y, MillimetersToPixels(68, 203), MillimetersToPixels(68, 203));
            g.DrawRectangle(pen, rect);
            g.DrawString("感謝您的購買!", font, brush, 10, y + 15);

            Rectangle printArea2 = new Rectangle(5, y+MillimetersToPixels(70, 203), MillimetersToPixels(30 * 1.1f, 203), MillimetersToPixels(15 * 1.1f, 203));//new RectangleF(0, 0, e.PageBounds.Width, e.PageBounds.Height);//
            g.DrawImage(bmp2, printArea2);

            Rectangle printArea1 = new Rectangle(5, y+MillimetersToPixels(70, 203) + MillimetersToPixels(17 * 1.1f, 203), MillimetersToPixels(40*1.1f, 203), MillimetersToPixels(40 * 1.1f, 203));//new RectangleF(0, 0, e.PageBounds.Width, e.PageBounds.Height);//
            g.DrawImage(bmp1, printArea1);

            //---
            //測試大圖
            /*
            y = 410 + 100 + 200 + 20;
            for (int i=0;i<100;i++)
            {
                g.DrawString(i+":", font, brush, 10, y);
                y += 20;
            }
            */
            //---測試大圖

            Font font01 = new Font("Arial", 1);
            g.DrawString("               .", font01, brush, 10, 1500);//故意拉長紙張 (500-300-y)/3.937=25mm

            /*
            BitmapBuf.Save("printer.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
            e.Graphics.DrawImage(BitmapBuf, 0, 0);//由於從BMP記憶體自建畫布,所以列印時就要從BMP記憶體進行
            //*/

            e.HasMorePages = false;
        };

        // 自訂紙張大小:寬 80mm,高 100mm(1mm ≈ 3.937 尺寸單位)
        int width = (int)(80 * 3.937);  // 約 315
        int height = 5000;//(int)(100 * 3.937); // 約 394

        PaperSize paperSize = new PaperSize("Custom_80mm", width, height);
        printDoc.DefaultPageSettings.PaperSize = paperSize;

        try
        {
            printDoc.Print();
            Console.WriteLine("列印工作已送出!");
        }
        catch (Exception ex)
        {
            Console.WriteLine("列印失敗:" + ex.Message);
        }
    }
}

One thought on “C# 印表機(PrintDocument的解析度 設定) ~ 像素(Pixels)/英吋(Inches)/毫米(Millimeters) 轉換函數

  1. 線上工具(OnLine Tool) : https://www.presspdf.com/zh-Hant/dpi-pixel-mm-converting

    =======================

    libreoffice calc (Excel) 公式

    像素 -> 英吋
    (pixels/dpi)

    像素 -> 毫米
    =ROUND((pixel/dpi)*25.4,3)

    毫米 -> 像素
    =ROUND(((mm/25.4)*dpi+0.5),0)

    ———————–

    libreoffice calc 四舍五入 取整數
    =ROUND(數字, 0)
    其中,數字 是你要四舍五入的數字,0 表示小數點後保留 0 位數,即取整數。

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *