Search code examples
htmlcssvb.netwebbrowser-controlwebview2

How HTML & CSS Code Can Be Used to Print POS on vb.net


I tried printing from HTML and CSS on a printer with the program language vb.net.

Please Guide Me

one more I want to add QR in footer section

This My code :

Public Class Form1
    Private Function ToHtml() As String
        Dim Pathimageheader As String = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logo.png")
        Dim Pathimagefooter As String = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Qr.png")
        Dim html =
            <html>
                <head>
                    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
                    <meta http-equiv="X-UA-Compatible" content="ie=edge"/>
                    <title>Receipt example</title>
                    <link rel="stylesheet" href="style.css"/>
                </head>
                <style>
                {
    font-size: 12px;
    font-family: 'Times New Roman';
}
td,
th,
tr,
table {
    border-top: 1px solid black;
    border-collapse: collapse;
}

td.description,
th.description {
    width: 75px;
    max-width: 75px;
}

td.quantity,
th.quantity {
    width: 40px;
    max-width: 40px;
    word-break: break-all;
}

td.price,
th.price {
    width: 40px;
    max-width: 40px;
    word-break: break-all;
}

.centered {
    text-align: center;
    align-content: center;
}

.ticket {
    width: 155px;
    max-width: 155px;
}

img {
    max-width: inherit;
    width: inherit;
}
</style>
                <body>
                    <div class="ticket">
                        <img src=<%= Pathimageheader %> alt="logo"></img>
                        <p class="centered">RECEIPT EXAMPLE
                        <br>Address line 1
                        </br><br>Address line2</br></p>
                        <table>
                            <thead>
                                <tr>
                                    <th class="quantity">Q.</th>
                                    <th class="description">Description</th>
                                    <th class="price">$$</th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr>
                                    <td class="quantity">1.00</td>
                                    <td class="description">ARDUINO UNO R3</td>
                                    <td class="price">$25.00</td>
                                </tr>
                                <tr>
                                    <td class="quantity">2.00</td>
                                    <td class="description">JAVASCRIPT BOOK</td>
                                    <td class="price">$10.00</td>
                                </tr>
                                <tr>
                                    <td class="quantity">1.00</td>
                                    <td class="description">STICKER PACK</td>
                                    <td class="price">$10.00</td>
                                </tr>
                                <tr>
                                    <td class="quantity"></td>
                                    <td class="description">TOTAL</td>
                                    <td class="price">$55.00</td>
                                </tr>
                            </tbody>
                        </table>
                        <p class="centered">Thanks for your purchase!
                             <br>parzibyte.me/blog</br></p>
                        <img src=<%= Pathimagefooter %> alt="logo"></img>
                    </div>
                </body>
            </html>

        Return html.ToString()
    End Function
 Private Sub BtnPrint_Click(sender As Object, e As EventArgs) Handles BtnPrint.Click
    
        myWebBrowser.DocumentText = ToHtml()

    End Sub
 Private Sub myWebBrowser_DocumentCompleted(ByVal sender As Object, ByVal e As WebBrowserDocumentCompletedEventArgs) Handles myWebBrowser.DocumentCompleted
        myWebBrowser.Parent = Me
        myWebBrowser.Visible = False
        myWebBrowser.ShowPrintPreviewDialog()
    End Sub

Desired result (without botton)

sorry I can't post the original html and css code because of an error at the time of posting but below is the link of the html and css code

link

enter image description here

enter image description here

result after update code

result after update code

RESULT AFTER UPDATE CODE LATEST

RESULT AFTER UPDATE CODE LATEST

RESULT FROM ANSWER

Qrcode.png

print screen dialog

print screen dialog


Solution

  • The WebBrowser control is quite old and may not support some of the newer styling. You may consider using the WebView2 control instead. Also, it appears that you've included style information twice - once as a link to a Style Sheet, and a second time in the HTML.

    The following shows how to use JavaScript, CSS, and HTML to create a receipt in VB.NET. It's an implementation of the code referenced in the OP - Print receipt in thermal printer using JavaScript, CSS & HTML. The code below uses NuGet package WebView2 to display the receipt. See the comments throughout the code for more information.

    VS 2022:

    Create a new Windows Forms App (.NET Framework) project

    Open Solution Explorer

    • In VS menu, click View
    • Select Solution Explorer

    Download/install NuGet package: Microsoft.Web.WebView2

    • In Solution Explorer, right-click <project name> and select Manage NuGet Packages...
    • Click Browse tab
    • Search for Microsoft.Web.WebView2
    • Click Install

    Create Templates folder

    • In Solution Explorer, right-click <project name>
    • Select Add
    • Select New Folder...
    • Rename folder: Templates

    Open Properties Window

    • In VS menu, click View
    • Select Properties Window

    Add logo image to Templates folder: (name: logo.png)

    • In Solution Explorer, right-click Templates
    • Select Add
    • Select Existing Item...
    • In the drop-down (lower-right) change the filter to Image Files(...) and select your logo image (ex: logo.png)
    • In Solution Explorer, under the Templates folder, select the logo image (ex: logo.png)
    • In the Properties Window, set Build Action: Content and Copy to Output Directory: Copy Always

    Add QR code image to Templates folder: (name: qrCode.jpg)

    • In Solution Explorer, right-click Templates
    • Select Add
    • Select Existing Item...
    • In the drop-down (lower-right) change the filter to Image Files(...) and select your logo image (ex: qrCode.jpg)
    • In Solution Explorer, under the Templates folder, select the QR code image (ex: qrCode.jpg)
    • In the Properties Window, set Build Action: Content and Copy to Output Directory: Copy Always

    Note: If you'd like to generate a QR code programmatically, see this post.

    Add Style Sheet to Templates folder: (name: style.css)

    • In Solution Explorer, right-click Templates
    • Select Add
    • Select New Item...
    • On left side expand Common Items. Then click Web.
    • Select Style Sheet (name: style.css)
    • In the Properties Window, set Build Action: Content and Copy to Output Directory: Copy Always

    style.css:

    * {
        font-size: 12px;
        font-family: 'Times New Roman';
    }
    
    td,
    th,
    tr,
    table {
        border-top: 1px solid black;
        border-collapse: collapse;
    }
    
        td.description,
        th.description {
            width: 75px;
            max-width: 75px;
        }
    
        td.quantity,
        th.quantity {
            width: 40px;
            max-width: 40px;
            word-break: break-all;
        }
    
        td.price,
        th.price {
            width: 40px;
            max-width: 40px;
            word-break: break-all;
        }
    
    .centered {
        text-align: center;
        align-content: center;
    }
    
    .ticket {
        width: 155px;
        max-width: 155px;
    }
    
    img {
        max-width: inherit;
        width: inherit;
    }
    
    @media print {
        .hidden-print,
        .hidden-print * {
            display: none !important;
        }
    }
    

    Add JavaScript file to Templates folder: (name: printReceipt.js)

    • In Solution Explorer, right-click Templates
    • Select Add
    • Select New Item...
    • On left side expand Common Items. Then click Web.
    • Select JavaScript File (name: printReceipt.js)
    • In the Properties Window, set Build Action: Content and Copy to Output Directory: Copy Always

    printReceipt.js:

    const $btnPrint = document.querySelector("#btnPrint");
    $btnPrint.addEventListener("click", () => {
        window.print();
    });
    

    Add receipt.html to Templates folder:

    • In Solution Explorer, right-click Templates
    • Select Add
    • Select New Item...
    • On left side expand Common Items. Then click Web.
    • Select HTML Page (name: receipt.html)
    • In the Properties Window, set Build Action: Content and Copy to Output Directory: Copy Always

    Note: In the HTML, I've removed the table data, and replaced it with a placeholder ("rowsPlaceHolder"). In VB.NET, we'll generate the HTML that goes here, and replace "rowsPlaceHolder" with the HTML. The paths for the style sheet and JavaScript file are relative to this HTML file, so either change the paths as necessary, or ensure that the HTML file is in the same folder as the style sheet (.css) and JavaScript file (.js).

    receipt.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <link rel="stylesheet" href="style.css">
        <title>Receipt example</title>
    </head>
    <body>
        <div class="ticket">
            <img src="./logo.png" alt="Logo">
            <p class="centered">
                RECEIPT EXAMPLE
                <br>Address line 1
                <br>Address line 2
            </p>
            <table>
                <thead>
                    <tr>
                        <th class="quantity">Q.</th>
                        <th class="description">Description</th>
                        <th class="price">$$</th>
                    </tr>
                </thead>
                <tbody>
                    rowsPlaceHolder
                </tbody>
            </table>
            <p class="centered">
                Thanks for your purchase!
                <br />
                <img src="qrCode.jpg" alt="QRCode" />
            </p>
        </div>
        <button id="btnPrint" class="hidden-print">Print</button>
        <script src="printReceipt.js"></script>
    </body>
    </html>
    

    In Solution Explorer, you should see the following:

    enter image description here


    Add a Form to the project (name: FrmReceipt.vb)

    Note: This form will host the WebView2 browser control which will display the receipt.

    • In Solution Explorer, right-click <project name>
    • Select Add
    • Select New Item...
    • On left side click Common Items.
    • Select Form (Windows Form) (name: FrmReceipt.vb)
    • Double-click the form to add the Load event handler
    • Resize the form as desired

    Open the Toolbox

    • In VS menu, select View
    • Select Toolbox

    Add WebView2 to FrmReceipt (name: webView21)

    • In Solution Explorer, right-click FrmReceipt.vb and select View Designer.
    • In the Toolbox, scroll to the top and expand WebView2 Windows Forms Control
    • Drag WebView2 control onto FrmReceipt
    • On the form, click the WebView2 control to select it
    • In the Properties Window, set Dock: Fill

    FrmReceipt.vb:

    Note: In the code below, you'll notice that the async keyword has been added to the Load event handler.

    Imports Microsoft.Web.WebView2.WinForms
    
    Public Class FrmReceipt
    
        Private appTempFolder As String = String.Empty
        Private receiptFilename As String = String.Empty
    
        Public Sub New(receiptFilename As String)
    
            ' This call is required by the designer.
            InitializeComponent()
    
            ' Add any initialization after the InitializeComponent() call.
            Me.receiptFilename = receiptFilename
    
            'set value
            appTempFolder = System.IO.Path.GetDirectoryName(receiptFilename)
            Debug.WriteLine($"FrmReceipt appTempFolder: {appTempFolder}")
        End Sub
    
        Private Async Sub FrmReceipt_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Debug.WriteLine($"WebView2 version: {GetWebView2Version()}")
    
            'set UserDataFolder
            WebView21.CreationProperties = New CoreWebView2CreationProperties() With {.UserDataFolder = appTempFolder}
    
            'explicitly initialize CoreWebView2
            Await WebView21.EnsureCoreWebView2Async()
    
            'display receipt
            WebView21.Source = New Uri($"file:///{receiptFilename}")
        End Sub
    
        Public Function GetWebView2Version() As String
            Dim webView2Assembly As System.Reflection.Assembly = GetType(WebView2).Assembly
            Return FileVersionInfo.GetVersionInfo(webView2Assembly.Location).ProductVersion
        End Function
    End Class
    

    One can use the following to generate the receipt:

    Note: The code below will go in the main form (ex: Form1.vb). If desired one can rename Form1.vb to something such as FrmMain.vb.

    Private appTempFolder As String = System.IO.Path.Combine(System.IO.Path.GetTempPath(), Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetExecutingAssembly().Location))
    Private templatesFolder As String = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Templates")
    Private addressLine1 As String = "123 Walnut Street"
    Private addressLine2 As String = "Some City, ABC 12345"
    
    Private Sub CreateReceipt()
        'for testing, we'll create a folder in the user's temp folder
        If Not System.IO.Directory.Exists(appTempFolder) Then
            System.IO.Directory.CreateDirectory(appTempFolder)
        End If
    
        'copy the following files so that they exist in the same folder as the .html file
        System.IO.File.Copy(System.IO.Path.Combine(templatesFolder, "logo.png"), System.IO.Path.Combine(appTempFolder, "logo.png"), True)
        System.IO.File.Copy(System.IO.Path.Combine(templatesFolder, "printReceipt.js"), System.IO.Path.Combine(appTempFolder, "printReceipt.js"), True)
        System.IO.File.Copy(System.IO.Path.Combine(templatesFolder, "qrCode.jpg"), System.IO.Path.Combine(appTempFolder, "qrCode.jpg"), True)
        System.IO.File.Copy(System.IO.Path.Combine(templatesFolder, "style.css"), System.IO.Path.Combine(appTempFolder, "style.css"), True)
    
        'get data
        'here a method is used to generate test data
        'but one could get data from a database instead
        Dim dt As DataTable = CreateTestData()
    
        'HTML filename
        Dim receiptFilename As String = System.IO.Path.Combine(appTempFolder, "receipt.html")
    
        'generate HTML and save to file
        GenerateHtml(dt, receiptFilename)
    
        'display receipt
        Dim receipt As FrmReceipt = New FrmReceipt(receiptFilename)
        receipt.Show()
    End Sub
    
    Private Function CreateTestData() As DataTable
        'create new instance
        Dim dt As DataTable = New DataTable("Items")
    
        'Add column: Qty
        Dim quantity As DataColumn = New DataColumn() With {.ColumnName = "Qty", .DataType = GetType(Double)}
        dt.Columns.Add(quantity)
    
        'Add column: Description
        Dim description As DataColumn = New DataColumn() With {.ColumnName = "Description", .DataType = GetType(String)}
        dt.Columns.Add(description)
    
        'Add column: Price
        Dim price As DataColumn = New DataColumn() With {.ColumnName = "Price", .DataType = GetType(Decimal)}
        dt.Columns.Add(price)
    
        Dim row As DataRow = Nothing
    
        row = dt.NewRow() 'create new row
        row("Qty") = 1
        row("Description") = "ARDUINO UNO R3"
        row("Price") = 25
        dt.Rows.Add(row) 'add to DataTable
    
        row = dt.NewRow() 'create new row
        row("Qty") = 2
        row("Description") = "JAVASCRIPT BOOK"
        row("Price") = 10
        dt.Rows.Add(row) 'add to DataTable
    
        row = dt.NewRow() 'create new row
        row("Qty") = 2
        row("Description") = "JAVASCRIPT BOOK"
        row("Price") = 10
        dt.Rows.Add(row) 'add to DataTable
    
        row = dt.NewRow() 'create new row
        row("Qty") = 1
        row("Description") = "STICKER PACK"
        row("Price") = 10
        dt.Rows.Add(row) 'add to DataTable
    
        Return dt
    End Function
    
    Private Sub GenerateHtml(dt As DataTable, outputFilename As String)
    
        'get HTML from template
        Dim html As String = File.ReadAllText(System.IO.Path.Combine(templatesFolder, "receipt.html"))
        Dim itemsHtml As StringBuilder = New StringBuilder()
        Dim total As Decimal = 0
    
        'create HTML for each item
        For i As Integer = 0 To dt.Rows.Count - 1
            'create HTML for each row
            itemsHtml.AppendFormat($"{Space(16)}<tr>{System.Environment.NewLine}")
    
            'convert to double
            Dim quantity As Double = 0
            Double.TryParse(dt(i)("Qty").ToString(), quantity)
    
            'convert to decimal
            Dim price As Decimal = 0
            Decimal.TryParse(dt(i)("Price").ToString(), price)
    
            'add data to table column
            itemsHtml.AppendFormat($"{Space(20)}<td class = ""quantity"">{quantity.ToString("N2")}</td>{System.Environment.NewLine}")
            itemsHtml.AppendFormat($"{Space(20)}<td class = ""description"">{dt(i)("Description")}</td>{System.Environment.NewLine}")
            itemsHtml.AppendFormat($"{Space(20)}<td class = ""price"">{price.ToString("N2")}</td>{System.Environment.NewLine}")
    
            itemsHtml.AppendFormat($"{Space(16)}</tr>{System.Environment.NewLine}")
    
            'add
            total += price
        Next
    
        'add HTML for Total
        itemsHtml.AppendFormat($"{Space(16)}<tr>{System.Environment.NewLine}")
    
        itemsHtml.AppendFormat($"{Space(20)}<td class = ""quantity""></td>{System.Environment.NewLine}")
        itemsHtml.AppendFormat($"{Space(20)}<td class = ""description"">TOTAL</td>{System.Environment.NewLine}")
        itemsHtml.AppendFormat($"{Space(20)}<td class = ""price"">${total.ToString("N2")}</td>{System.Environment.NewLine}")
    
        itemsHtml.AppendFormat($"{Space(16)}</tr>{System.Environment.NewLine}")
    
        'replace address
        html = html.Replace("Address line 1", addressLine1)
        html = html.Replace("Address line 2", addressLine2)
    
        'replace place holder with HTML for items
        html = html.Replace("rowsPlaceHolder", itemsHtml.ToString())
    
        'save
        System.IO.File.WriteAllText(outputFilename, html)
    End Sub
    
    Private Function Space(numSpaces As Integer) As String
        Return New String(" ", numSpaces)
    End Function
    

    Usage:

    CreateReceipt()
    

    Update:

    If one needs to adjust the size of an image, one can use MS Paint to resize the image prior to adding it to the Templates folder or one can use the width and height properties of the img tag in the HTML to specify the desired size. When setting these properties in the HTML, the width and height should be less than or equal to the width and height of the image.

    <img src="qrCode.jpg" alt="QRCode" width="75" height="75" />