Click here to Skip to main content
Click here to Skip to main content

Printing from a Xamarin.Android Application Developed with Visual Studio

, 15 Jul 2014
Rate this:
Please Sign up or sign in to vote.
Printing from a Xamarin.Android application developed with Visual Studio

Introduction

If you have ever had to develop a business application that targets the Android / mobile platform, you may have had to print from your application. Unlike printing from your desktop PC at home or work, you don't tend to connect your mobile device to a printer, so printing becomes a more difficult and problematic issue. In this article, I will describe how you can print from your Xamarin.Android application. Although the article was written with Xamarin.Android and C# in mind, the article lends itself just as easily to Eclipse and Java.

Background

This article uses a Star Micronics thermal printer. A thermal printer produces a digital image by heating thermal paper. The range from Star Micronics enable printing from web-based applications via HTTP requests. They are small, lightweight and have a very small memory footprint making them ideal for printing from mobile devices. They also support Bluetooth and so can be used wirelessly, making them even more appropriate for mobile device printing.

To use the printer in your application, you will firstly need to download the Star Micronics SDK. Once you have downloaded the SDK, you will need to add a reference the StarPrinter.dll assembly to your Visual Studio project.

A Note About Responsiveness

Before we get started, it is important to keep application responsiveness firmly in mind. The worst thing that can happen to your application is that it triggers an "Application Not Responding" (ANR) dialog. Within Android, the system guards against applications that are insufficiently responsive for a period of time by displaying a dialog stating your application has stopped responding.

Printing is exactly the sort of task that is likely to take relatively more time to complete than other tasks, and therefore a prime candidate for triggering an ANR dialog. You should therefore carefully consider how your application will perform printing tasks without triggering an ANR. You should not perform print tasks on the main UI thread, and instead consider another strategy such as implementing your print tasks using a Thread or AsyncTask instead.

A detailed discussion of Android application responsiveness is outside the scope of this article, but is certainly something that you need to consider when designing and implementing your application.

This article assumes familiarity with Android graphical elements such as Bitmap, Canvas, Paint, TextLayout and StaticLayout.

Adding Star Micronics to Your Application

To include Star Micronics print functionality in your application, you will need to add the following reference to your code:

using Com.Starmicronics.Stario;

Finding Your Star Micronics Bluetooth Printer

Before your application can use the printer, it will firstly have to find it. Star printers can be located using either Bluetooth or TCP (LAN) protocols. Although in practice your application will use Bluetooth, I have added an example of how you can also search for your printer using TCP for the sake of completeness.

new Thread(() =>
            {
                try
                {
                    IList<PortInfo> portList = StarIOPort.SearchPrinter("BT");
                    if (!portList.Any())
                    {
                        portList = StarIOPort.SearchPrinter("BT:DeviceName");
                    }
                    if (!portList.Any())
                    {
                        portList = StarIOPort.SearchPrinter("BT:MacAddress");
                    }
                    if (!portList.Any())
                    {
                        portList = StarIOPort.SearchPrinter("BT:Star Micronics");
                    }
                    if (!portList.Any())
                    {
                        portList = StarIOPort.SearchPrinter("TCP");
                    }

                    if (!portList.Any())
                    {
                        RunOnUiThread(() =>
                        ShowAlert("No printers found, connect on bluetooth first",
                            ToastLength.Long, Resource.Drawable.printer_cross));
                    }
                }
                catch (StarIOPortException ex)
                {
                    RunOnUiThread(() =>
                        Toast.MakeText(this, "Error finding printers: 
                        " + ex.Message, ToastLength.Long).Show());
                }
            }).Start();

To locate your Star printer, you need to invoke the SearchPrinter() function. This function returns a list of printers that it finds using the specified interface types to search. It will search for printers on LAN or paired Bluetooth devices. You will probably want to invoke this code at application startup.

Note how the printer search is executed on a Thread() so it does not occupy the main UI thread and possibly trigger an ANR. Note also that the mechanism invokes the SearchPrinter() function sequentially, specifying several different interface types. This gives your application a greater chance of successfully finding your printer.

IList<PortInfo> portList = StarIOPort.SearchPrinter(string target);

Valid values for the target parameter are:

  • BT
  • BT:<DeviceName>
  • BT:<MacAddress>
  • TCP
  • TCP:<IPAddress>

Where <DeviceName>, <MacAddress> and <IPAddress> are the device name, MAC address and IP address respectively. These can be specified optionally.

Finding a Printer Port

Once you have found the printer, you need to open a connection to it. The function GetPort() is used to accomplish this. If successful, it will return a handle to the printer port.

StarIOPort port = StarIOPort.GetPort(string portName, string portSettings, int timeoutMillisecs);
  • portName is the name of the printer found previously using the SearchPrinter() function
  • i.e. portList[0].PortName
  • portSettings is for either Ethernet or Bluetooth. For the purposes of this article, I will focus only on Bluetooth. If using a mini printer, then specify this with mini. This is required for all Bluetooth printers.
  • timeoutMillisecs is the timeout in milliseconds used when writing or reading from the port. 1000 milliseconds is 1 second.

Example usage:

StarIOPort port = StarIOPort.GetPort(portList[0].PortName, "mini", 10000);

Memory Considerations

Before proceeding and showing how to actually print from your printer, it is important to note that Android devices are low powered, low memory devices. As such, they lack the corresponding CPU and memory horse power of other devices such as a laptop or desktop PC. Memory limitations were the single biggest issue I experienced when implementing print functionality for the Android platform.

If the text required to be printed contains images (such as logos, boxes around the text, signatures, etc.), then you may want to consider creating a bitmap image and printing this image. Due to the memory limitations of Android devices, you may want to consider how often you print out these images. Initially, my applications threw "Out of memory" errors as I was printing the entire image list at the end of the print routine. I resolved this by building up a list of bitmaps and printing these one at a time to the printer.

Here is the class declaration for the bitmap list that the application used:

private static List<Bitmap> _imageList;

Here is the code to print your bitmap list:

//this is declared at the class level
private static readonly List<byte> InitialisePrinter = new List<byte> { Esc, 0x40 };

private static void PrintImageCollection(StarIOPort port)
{
    try
    {
        if (_imageList != null && _imageList.Any())
        {
            foreach (var bmp in _imageList)
            {
                var command = new List<byte>();
                var starBitmapReceipt = new StarBitmap(bmp, true, 832);
                command.AddRange(InitialisePrinter);
                command.AddRange(starBitmapReceipt.GetImageEscPosDataForPrinting(true, true));
                port.WritePort(command.ToArray(), 0, command.Count);
            }
            _bitmap.Dispose();
            _imageList.Clear();
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

The key method to note in this code snippet is WritePort(byte[] writeBuffer, int offset, int size).

WritePort(byte[] writeBuffer, int offset, int size);
  • writeBuffer is the array containing the data to be written
  • offset is the start offset for writing data
  • size is the amount of data that should be written to the pointer

Full Listing of a Print Class

In the example code below, some basic details are printed, i.e. name and address. Each piece of information to be printed is added to a bitmap image one-at-a-time. The bitmaps are added to an image list. The print routine iterates through this image list and prints the individual bitmaps.

using System;
using System.Collections.Generic;

using Android.Graphics;
using Android.Text;

using Com.Starmicronics.Stario;

public class Printing
{
    public PrintForm()
    {
        private static Canvas _canvas;
        private static Paint _paint;
        private static Bitmap _bitmap;
        private static TextPaint _textPaint;
        
        private static readonly List<byte> InitialisePrinter = new List<byte> { Esc, 0x40 };
        private static List<Bitmap> _imageList;
        private static readonly Bitmap.Config BitmapConfig = Bitmap.Config.Argb4444;
    
        public static void PrintDetails(StarIOPort port)
        {
            try
            {
                //we will assume that the methods SearchPrinter() and GetPort() have already been
                //invoked at application startup and were successful

                PrintText("\nMy Details", Bold, Layout.Alignment.AlignNormal, 26);
                PrintText("Name", String.Format("{0}", 
                "Dominic Burford"), 400, false, false, rowHeight);
                PrintText("Addr1", String.Format("{0}", 
                "1 High Street"), 400, false, false, rowHeight);
                PrintText("Addr2", String.Format("{0}", 
                "London"), 400, false, false, rowHeight);
                PrintText("Postcode", String.Format("{0}", 
                "XX1 1YY"), 400, false, false, rowHeight);
                
                _imageList.Add(_bitmap.Copy(BitmapConfig, false));
                NewBitmapImage(port);

                //to print more information you will need to repeat the above steps i.e.
                
                //PrintText("\nMy Further Details", Bold, Layout.Alignment.AlignNormal, 26);
                //PrintText("Further Details 1", String.Format("{0}", 
                "details 1"), 400, false, false, rowHeight);
                //PrintText("Further Details 2", String.Format("{0}", 
                "details 2"), 400, false, false, rowHeight);
                                
                //_imageList.Add(_bitmap.Copy(BitmapConfig, false));
                //NewBitmapImage(port);

                //etc 
            }
            catch(Exception ex)
            {
                throw ex;
            }
        }

        private static void NewBitmapImage(StarIOPort port)
        {
            try
            {
                if (port != null)
                    PrintImageCollection(port);

                _bitmap.Dispose();
                _bitmap = null;
                _bitmap = Bitmap.CreateBitmap(832, 10, BitmapConfig);
                _canvas = new Canvas(_bitmap);
                _canvas.DrawColor(Color.White);
                _canvas.Translate(0, 0);
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        private static void PrintImageCollection(StarIOPort port)
        {
            try
            {
                if (_imageList != null && _imageList.Any())
                {
                    foreach (var bmp in _imageList)
                    {
                        var command = new List<byte>();
                        var starBitmapReceipt = new StarBitmap(bmp, true, 832);
                        command.AddRange(InitialisePrinter);
                        command.AddRange(starBitmapReceipt.GetImageEscPosDataForPrinting(true, true));
                        port.WritePort(command.ToArray(), 0, command.Count);
                    }
                    _bitmap.Dispose();
                    _imageList.Clear();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private static void PrintText(string text, Typeface typeface, 
            Layout.Alignment alignment, int textSize, int width = 832)
        {
            try
            {
                using (var details = _bitmap.Copy(BitmapConfig, false))
                {
                    if (_paint == null)
                        _paint = new Paint();

                    _paint.SetTypeface(typeface);
                    _paint.TextSize = textSize;
                    _textPaint = new TextPaint(_paint);

                    var statlayout = new StaticLayout(text, _textPaint, width, 
                                     alignment, 1, 0, false);

                    _bitmap = Bitmap.CreateBitmap(832, statlayout.Height + 
                              details.Height + 30, BitmapConfig);

                    _canvas = new Canvas(_bitmap);
                    _canvas.DrawColor(Color.White);
                    _canvas.Translate(0, 0);
                    _canvas.DrawBitmap(details, 0, 0, _paint);
                    _canvas.Translate(0, details.Height);

                    statlayout.Draw(_canvas);

                    _canvas.Translate(0, -details.Height);

                    details.Dispose();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}

You would need to repeat the below steps for each section of information you wanted to print if you had other sections of information to print.

//repeat this for each piece of information you want to print
PrintText("\nSome text", Bold, Layout.Alignment.AlignNormal, 26);

//once you have collected your print information,
//you then add the corresponding bitmaps to your image collection for printing
_imageList.Add(_bitmap.Copy(BitmapConfig, false));
NewBitmapImage(port);

Summary

Hopefully, this article has given you sufficient information to start printing from your own Xamarin.Android application. Feel free to leave a comment if you would like me to further elaborate on anything within this article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Dominic Burford
Software Developer (Senior)
United Kingdom United Kingdom
I am a professional software engineer and architect with over fifteen years extensive commercial development experience, focusing on the design, development and testing of software solutions using Microsoft technologies.
 
I have experience of building a wide variety of applications from desktop to client-server to web to mobile and tablet using Visual Studio.
 
I have experience of architecting scalable, distributed, high volume web applications that are accessible from multiple devices due to their responsive web design.
 
I have developed enterprise mobile applications for the Android platform delivering real-time data securely to tablet devices via WCF services.
 
I am proficient in .NET, ASP.NET (VB.NET / C#), Windows and Web Services, WCF, SQL Server, LINQ and other Microsoft technologies. I am also familiar with HTML, Javascript/JQuery, XML, XSLT and many other web related technologies.
 
Visit my website here http://www.dominicburford.co.uk
Visit my Github repositories here https://github.com/DomBurf
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
QuestionWhich SDK did you import? PinmemberMember 8029214-Aug-14 9:11 
AnswerRe: Which SDK did you import? PinmemberDominic Burford4-Aug-14 12:29 
QuestionCould not find StarPrinter.dll in the SDK PinmemberRamanaNV20-Jul-14 4:47 
AnswerRe: Could not find StarPrinter.dll in the SDK PinmemberDominic Burford20-Jul-14 9:36 
GeneralRe: Could not find StarPrinter.dll in the SDK PinmemberRamanaNV21-Jul-14 9:00 
GeneralRe: Could not find StarPrinter.dll in the SDK PinmemberDominic Burford21-Jul-14 11:22 
GeneralRe: Could not find StarPrinter.dll in the SDK PinmemberRamanaNV21-Jul-14 17:51 
QuestionFlexibility PinmemberEd(Member 1767792)16-Jul-14 10:05 
AnswerRe: Flexibility PinmemberDominic Burford17-Jul-14 1:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140814.1 | Last Updated 15 Jul 2014
Article Copyright 2014 by Dominic Burford
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid