DYMO Label Inside Out

December 16, 2011

Printing QR-code: Part 2

Filed under: DYMO Label Framework,SDK Samples — Vladimir @ 7:50 am
Tags: , ,

The previous post demonstrated different ways of printing QR-code from a .NET application. This blog post will demonstrate how to achieve the same goal from a web application. The complete sample is available here. The corresponding JavaScript is here.

Prerequisites

First, make sure the latest DYMO Label software is installed. It is always available on DYMO web-site, at the time of writing it is version 8.3.1.

Use Barcode Object

The easiest way to print QR-code is to use built-in support for QR-code in DYMO Label Framework. First, design your label using DYMO Label software. Unfortunately, DYMO Label itself does not have ability to specify QR-code barcode type in the UI yet. So, add the Barcode object to the label and put it into desired position. Don’t specify the barcode symbology, use the default Code39. Save the label in to a file, open the file in any XML editor and change thetag to “QRCode”.

<BarcodeObject>
    <Name>Barcode</Name>
    <ForeColor Alpha="255" Red="0" Green="0" Blue="0" />
    <BackColor Alpha="0" Red="255" Green="255" Blue="255" />
    <LinkedObjectName></LinkedObjectName>
    <Rotation>Rotation0</Rotation>
    <IsMirrored>False</IsMirrored>
    <IsVariable>False</IsVariable>
    <Text></Text>
   <Type>QRCode</Type>
    <Size>Large</Size>
    <TextPosition>None</TextPosition>
    <TextFont Family="Arial" Size="8" Bold="False" Italic="False" Underline="False" Strikeout="False" />
    <CheckSumFont Family="Arial" Size="8" Bold="False" Italic="False" Underline="False" Strikeout="False" />
    <TextEmbedding>None</TextEmbedding>
    <ECLevel>0</ECLevel>
    <HorizontalAlignment>Left</HorizontalAlignment>
    <QuietZonesPadding Left="0" Top="0" Right="0" Bottom="0" />
</BarcodeObject>

See Barcode.label from the sample. After the label is ready, the actual steps to print it is quite easy: open the label, set desired data, print. Here is a snippet from the sample:

printButton.onclick = function()
{
    try
    {
        if (!barcodeLabel)
            throw "Load label before printing";

        if (!printersSelect.value)
            throw "Select printer.";

        barcodeLabel.setObjectText('Barcode', 'http://developers.dymo.com');
        barcodeLabel.print(printersSelect.value);
    }
    catch(e)
    {
        alert(e.message || e);
    }
}

First, we check that the label is loaded and the printer is selected. Next, the barcode data is set to be the blog’s URL. And finally, the label is printed.

Use Image Object

Printing QR-code by using Barcode object is easy. The only drawback, it is hard to control the actual barcode size. tag can be used for that but it support only three predefined sizes Small/Medium/Large, but still the overall size will depend on the actual barcode data. The longer the data string, the larger is the barcode. So, the idea is to use some library to generate QR-code image of desired size, and then print it using the Image object. As before, design a label using DYMO Label software. Put an Image object on the label where the barcode should be printed. Set the Image objet size to the desired barcode size. When specifying the barcode image size in pixels calculate it based on the printer resolution, that is 300 dpi for LabelWriter printers and 180 dpi for Tape printers. For example, if you want the barcode to be 1” in size, specify the barcode image size as 300×300 pixels. See BarcodeAsImage.label from the sample project.

Image object accepts image data as a string that contains base64-encoded png stream. The question is, how to get/generate this string. Again, there are several ways of doing that.

Generate and base64-encode QR-code image on the server-side

One way is to generate QR-code image on the server using some library. Then encode the image using base64 and return it to the client as a string. Finally, on the client side, call setObjectText on the Image object and print.

printAsImageButton.onclick = function()
{
    try
    {
        if (!barcodeAsImageLabel)
            throw "Load label before printing";

        if (!printersSelect.value)
            throw "Select printer";

        $.get("qr.base64", function(qr)
        {
            try
            {
                barcodeAsImageLabel.setObjectText('Image', qr);

                barcodeAsImageLabel.print(printersSelect.value);
            }
            catch(e)
            {
                alert(e.message || e);
            }
        }, "text");

    }
    catch(e)
    {
        alert(e.message || e);
    }
}

In the sample, we just request “qr.base64” resource that contains precalculated QR-code image for “http://developers.dymo.com”. In real application, you will probably pass the data to be encoded as a resource parameter.

Generate QR-code image on the server-side and base64-encode it on the client-side.

Base64-encoded strings are larger then binary png data. So, to reduce network traffic, we can return original png data from the server and base64-encode it on the client. To encode the data we will create , render our image on it, and then get encoded data using canvas.toDataURL() method.

printAsImageCanvasButton.onclick = function()
{
    try
    {
        if (!barcodeAsImageLabel)
            throw "Load label before printing";

        if (!printersSelect.value)
            throw "Select printer.";

        var img = new Image();
        img.onload = function()
        {
            try
            {
                var canvas = document.createElement('canvas');
                canvas.width = img.width;
                canvas.height = img.height;

                var context = canvas.getContext('2d');
                context.drawImage(img, 0, 0);

                var dataUrl = canvas.toDataURL('image/png');
                var pngBase64 = dataUrl.substr('data:image/png;base64,'.length);

                barcodeAsImageLabel.setObjectText('Image', pngBase64);
                barcodeAsImageLabel.print(printersSelect.value);
            }
            catch(e)
            {
                alert(e.message || e);
            }
        };
        img.onerror = function()
        {
            alert('Unable to load "qr.png"');
        };
        img.src = 'qr.png';
    }
    catch(e)
    {
        alert(e.message || e);
    }
}

Note: image loading is asynchronous process. So, we can’t just assign img.src property and immediately draw it on a canvas; we have to wait until the image is loaded completely from the server. To handle that, we do main work in onload handler. also, toDataURL returns data url, to get the data itself, we have to remove the url prefix.

Again, as in the previous case, qr.png resource contains recalculated QR-code image for “http://developers.dymo.com”. In real application, you will probably pass the data to be encoded as a resource parameter.

A drawback of this method is that it requires support in the browser. All major browsers already support it, but be aware that in Internet Explorer it is supported starting from version 9 only.

Use third-party service

Instead of generating QR-code image on your own server, is it possible to use one of the many free online QR-code generator/service? The answer is yes, but it is even more trickier than the previous way. The problem, as usual in web development, is the security. But default is it not possible to grab canvas pixels if an image from a different domain has been drawn on the canvas. It is possible to overcome it, but it requires three parties to participate properly. First, your JavaScript has to set img.crossOrigin property to ‘anonymous’. This will tell the browser that you are trying to access a cross-domain resource, so the browser can send appropriate request headers, e.g. the browser will not send cookies. Next, the server itself should allow its resources to be accessible from other domains. Only few of many QR-code online generators do allow it. And the last, the browser itself should support CORS for . It is very recent addition to the standards, so at the time of writing only Chrome does support it. In any other browsers you will still get “security exception” error. Here are some links regarding and cross-domain limitations:

http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#security-with-canvas-elements

http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html

http://code.google.com/p/chromium/issues/detail?id=82042

Update (2011-12-20): works in Firefox 9 as well.

printAsImageCanvas2Button.onclick = function()
{
    try
    {
        if (!barcodeAsImageLabel)
            throw "Load label before printing";

        if (!printersSelect.value)
            throw "Select printer.";

        var img = new Image();
        img.crossOrigin = 'anonymous';
        img.onload = function()
        {
            try
            {
                var canvas = document.createElement('canvas');
                canvas.width = img.width;
                canvas.height = img.height;

                var context = canvas.getContext('2d');
                context.drawImage(img, 0, 0);

                var dataUrl = canvas.toDataURL('image/png');
                var pngBase64 = dataUrl.substr('data:image/png;base64,'.length);

                barcodeAsImageLabel.setObjectText('Image', pngBase64);
                barcodeAsImageLabel.print(printersSelect.value);
            }
            catch(e)
            {
                alert(e.message || e);
            }
        };
        img.onerror = function()
        {
            alert('Unable to load qr-code image');
        };
        img.src = 'https://chart.googleapis.com/chart?chs=300x300&cht=qr&chl=http%3A//developers.dymo.com&choe=UTF-8';
    }
    catch(e)
    {
        alert(e.message || e);
    }
}

The code is very similar to the previous example. The only difference is that we set img.crossOrigin property and we use Google’s Infographics API to generate the qr-code image. Notice that in this example the image is generated dynamically, and barcode data is passed as the part of the url.

Pure client-side JavaScript

At the time of writing, it seems there is no self-contained pure JavaScript solutions to create QR-code images using <canvas> completely on the client-side. In the future it might be one more way of doing QR-code printing.

Conclusion

It is quite simple to print QR-code barcode even if built-in support is somewhat limited.

November 29, 2011

Printing QR-code: Part 1

Filed under: DYMO Label Framework,SDK Samples — Vladimir @ 8:14 am
Tags: , , ,

This blog post will demonstrate how it is easy to print a label with a QR-code barcode from any .NET application. Even more, it will show how to do that in two different ways. The sample VS 2008 project is available here.

Prerequisites

First, make sure the latest DYMO Label software is installed. It is always available on DYMO web-site, at the time of writing it is version 8.3.1. Next, in Visual Studio create a new .NET project and add a reference to DYMO.Label.Framework assembly. This will make possible to use DYMO Label Framework API in the project.

Use Barcode Object

The easiest way to print QR-code is to use built-in support for QR-code in DYMO Label Framework. First, design your label using DYMO Label software. Unfortunately, DYMO Label itself does not have ability to specify QR-code barcode type in the UI yet. So, add the Barcode object to the label and put it into desired position. Don’t specify the barcode symbology, use the default Code39. Save the label in to a file, open the file in any XML editor and change the <Type> tag to “QRCode”.

<BarcodeObject>
    <Name>Barcode</Name>
    <ForeColor Alpha="255" Red="0" Green="0" Blue="0" />
    <BackColor Alpha="0" Red="255" Green="255" Blue="255" />
    <LinkedObjectName></LinkedObjectName>
    <Rotation>Rotation0</Rotation>
    <IsMirrored>False</IsMirrored>
    <IsVariable>False</IsVariable>
    <Text></Text>
    <Type>QRCode</Type>
    <Size>Large</Size>
    <TextPosition>None</TextPosition>
    <TextFont Family="Arial" Size="8" Bold="False" Italic="False" Underline="False" Strikeout="False" />
    <CheckSumFont Family="Arial" Size="8" Bold="False" Italic="False" Underline="False" Strikeout="False" />
    <TextEmbedding>None</TextEmbedding>
    <ECLevel>0</ECLevel>
    <HorizontalAlignment>Left</HorizontalAlignment>
    <QuietZonesPadding Left="0" Top="0" Right="0" Bottom="0" />
</BarcodeObject>

See Barcode.label file in the sample project. After the label is ready, the actual steps to print it is quite easy: open the label, set desired data, print. Here is a snippet from the sample:

private void PrintBarcodeButton_Click(object sender, RoutedEventArgs e)
{
    // load label template
    var label = DYMO.Label.Framework.Label.Open(
        Application.GetResourceStream(
            new Uri("Barcode.label", UriKind.Relative)).Stream);

    // set barcode data
    label.SetObjectText("Barcode", "http://developers.dymo.com");

    // print
    label.Print(PrintersComboBox.Text);
}

First, label is loaded from a file, stored as a resource in the application assembly. Next, the barcode data is set to be the blog’s URL. And finally, the label is printed on the printer selected in the UI.

Use Image Object

Printing QR-code by using Barcode object is easy. The only drawback, it is hard to control the actual barcode size. <Size> tag can be used for that but it support only three predefined sizes Small/Medium/Large, but still the overall size will depend on the actual barcode data. The longer the data string, the larger is the barcode. So, the idea is to use some library to generate QR-code image of desired size, and then print it using the Image object. As before, design a label using DYMO Label software. Put an Image object on the label where the barcode should be printed. Set the Image’s Scale Mode to None to avoid image scaling and possible problems with the scanning/reading of the printed barcode. See BarcodeAsImage.label from the sample project. Then use selected library to generate the QR-code image. When specifying the barcode image size in pixels calculate it based on the printer resolution, that is 300 dpi for LabelWriter printers and 180 dpi for Tape printers. For example, if you want the barcode to be 1” in size, specify the barcode image size as 300×300 pixels. Actuals API calls are very similar to the first case.

private void PrintBarcodeAsImageButton_Click(object sender, RoutedEventArgs e)
{
    // load label template
    var label = DYMO.Label.Framework.Label.Open(
        Application.GetResourceStream(
            new Uri("BarcodeAsImage.label", UriKind.Relative)).Stream);

    // set data as a barcode image
    var imageStream = Application.GetResourceStream(
            new Uri("qr.png", UriKind.Relative)).Stream;

    label.SetImagePngData("Image", imageStream);

    // print
    label.Print(PrintersComboBox.Text);
}

First, label is loaded from a file, stored as a resource in the application assembly. Next, the barcode image is “generated”; for the simplicity, already created png file is used instead of library calls. Next, the image data is assigned to the Image object. And finally, the label is printed on the printer selected in the UI.

Conclusion

It is quite simple to print QR-code barcode even if built-in support is somewhat limited. The next post will show how to do the same thing by using DYMO Label JavaScript library.

November 17, 2011

JavaScript Library Samples: Printers and Multiple Labels Printing

Filed under: DYMO Label Framework,SDK Samples — Vladimir @ 5:29 am
Tags: ,

Here is one more sample demonstrates capabilities of DYMO Label JavaScript library. The correspondent JavaScript file is here.

Getting Printers

First, the sample shows how to retrieve a list of available DYMO printers. For each printer it shows all the available properties. To get the printer list use dymo.label.framework.getPrinters function. The function returns an array contains information regarding each printer. The sample calls getPrinters and then put all the information onto a table, see createPrintersTable() for details.

Note: There are helpful function to filter the result list to contain only LabelWriter or Tape printers; use dymo.label.framework.getLabelWriterPrinters or dymo.label.framework.getTapePrinters accordingly. This might be useful if your application is designed to print on die-cut labels or D1 tapes only.

Print Multiple Labels

Next, the sample shows how to print multiple labels at once, in one print job. The sample leverages the library’s LabelSet functionality do archive that. For each printer the sample creates one label set record represent data to be printed on one label. also the sample demonstrates how to apply different text styles to the print data. It uses a feature called text markup, the ability to apply formatting attributes/tags very similar to HTML ones. 

// create label set to print printers' data
var labelSetBuilder = new dymo.label.framework.LabelSetBuilder();
for (var i = 0; i < printers.length; i++)
{
    var printer = printers[i];

    // process each printer info as a separate label
    var record = labelSetBuilder.addRecord();

    // compose text data
    // use framework's text markup feature to set text formatting
    // because text markup is xml you can use any xml tools to compose it
    // here we will use simple text manipulations to avoid cross-browser compatibility.
    var info = "<font family='Courier New' size='14'>"; // default font
    info = info + "Printer: <b>" + printer.name + "\n</b>"; 
    info = info + "PrinterType: " + printer.printerType;
    info = info + "\n<font size='10'>is local: " + printer.isLocal;
    info = info + "\nis online: " + printer.isConnected + "</font>";

    if (typeof printer.isTwinTurbo != "undefined")
    {
        if (printer.isTwinTurbo)
            info = info + "<i><u><br/>The printer is TwinTurbo!!!</u></i>";
        else
            info = info + "<font size='6'><br/>Oops, the printer is NOT TwinTurbo</font>";
    }

    if (typeof printer.isAutoCutSupported != "undefined")
    {
        if (printer.isAutoCutSupported)
            info = info + "<i><u><br/>The printer supports auto-cut!!!</u></i>";
        else
            info = info + "<font size='6'><br/>The printer does not supports auto-cut</font>";
    }

    info = info + "</font>";

    // when printing put info into object with name "Text"
    record.setTextMarkup("Text", info);
}

See print() function for a complete sample.

Note: Here is another blog post regarding using text markup. And one more regarding printing multiple labels.

October 7, 2011

DYMO Label Framework JavaScript Library 1.2.4

Filed under: DYMO Label Framework,News,SDK News — Vladimir @ 6:29 am
Tags: , , ,

A new version of DYMO Label Framework JavaScript library is available.

This version adds support for Opera 11.51 on Mac and Windows.

The js script file is available from http://labelwriter.com/software/dls/sdk/js/DYMO.Label.Framework.1.2.4.js.

The http://labelwriter.com/software/dls/sdk/js/DYMO.Label.Framework.latest.js has been updated to version 1.2.4 as well.

October 4, 2011

DYMO Label Framework JavaScript Library: Advanced Text Formatting

Filed under: DYMO Label Framework,SDK Samples — Vladimir @ 5:37 am
Tags: , , , ,

There are two ways of providing dynamic text data to be printed on your labels. In both cases the text can be “styled”, so different parts of the text will use different fonts, sizes and/or styles.

The first way covers most use cases for text formatting needs, it is simple, and, of cause, has some limitations. The limitation is that it supports line-by-line formatting only. So, each line can have its own formatting, but all characters in the same line will use the same formatting. If this is OK for your application, then here are the steps needed to utilize this method. first, you have to design you label layout/template. The easiest way to design a label is by using DYMO Label software. While designing, type a sample data for a label object, and apply some formatting, on line by line basis, e.g. make the first line bold, save the file, and put it on your server. 

image

Those are manual steps, now we will need some JavaScript. Load the label by using openLabelXml. Now you can set your real data by using setLabelText or, if you need to print multiple labels, by using a LabelSet. You pass a plain string without any formatting to the setLabelText method, and the library will apply line-by-line formatting for you based on the sample data in the label file. For example, if you call setLabelText(‘Will E. Coyote\nACME Birding\n2200 Desert Meadows Way\nLas Vegas, NV 89122’), the output will be like that:

image

The second way to format the text is by using so called “Text Markup” feature. It is some what more complex than the first formatting method, but in return you have the full control over the font attributes and can do character-by-character formatting. First, you design your label as described above, but you don’t have to specify any sample data. Next you have to construct a “text markup”.  A text markup is an xml string contains tags controlling font attributes, plus plain text data. The Supported tags are ones similar to HTML tags: <font>, <b>, <i>, <u>, <s>, <br>. Full xml-schema definition is available here. After you have the markup text, you can print it by using a LabelSet and setTextMarkup method.

var labelSet = new dymo.label.framework.LabelSetBuilder();
var record = labelSet.addRecord();

var textMarkup = '...';
record.setTextMarkup('Text', textMarkup);
label.print('DYMO LabelWriter 450', null, labelSet.toString());

Here is an example demonstrates different formatting capabilities: http://labelwriter.com/software/dls/sdk/samples/js/TextMarkup/TextMarkup.html, and the corresponded JavaScript http://labelwriter.com/software/dls/sdk/samples/js/TextMarkup/TextMarkup.js. Type anything into the “Text to Print” text box and click on any button below. The output should correspond to the button’s caption. The corresponded text markup will be copied to the “Text Markup” text box, so you can examine it without going into JavaScript debugger. Also, you can just type any text markup in the box and print it by clicking on “Print text markup” button. Just make sure it is a correct xml and correct markup. If it is not, a runtime error/exception is thrown.

September 16, 2011

DYMO Label Framework JavaScript Library 1.2.3

Filed under: DYMO Label Framework,News,SDK News — Vladimir @ 1:40 am
Tags: , , ,

A new version of DYMO Label Framework JavaScript library is available.

This version improves detection of supported browsers, or more precise unsupported ones. There is a known problem with Safari 5.1 running in 32-bit mode on both Mac OS X 10.6 and 10.7. Before version 1.2.3 the library did not detect this problem. Now, the call to dymo.label.framework.checkEnvironment() will return an error.

The js script file is available from http://labelwriter.com/software/dls/sdk/js/DYMO.Label.Framework.1.2.3.js.

The http://labelwriter.com/software/dls/sdk/js/DYMO.Label.Framework.latest.js has been updated to version 1.2.3 as well.

September 7, 2011

DYMO Label Framework JavaScript Library 1.2.2

Filed under: DYMO Label Framework,News,SDK News — Vladimir @ 5:00 am
Tags: ,

A new version of DYMO Label Framework JavaScript library is available.

Thanks to our friends at lambslist.com a subtle bug in Mac version of DYMO Label software has been discovered (and fixed). The problem manifests itself at print time, when the label data is printed using the default font instead of one specified in the label file. The fix for DYMO Label software is scheduled for the next release, 8.4. In the meantime the js script library has been updated to include a workaround for the problem.

The js script file is available from http://labelwriter.com/software/dls/sdk/js/DYMO.Label.Framework.1.2.2.js.

The http://labelwriter.com/software/dls/sdk/js/DYMO.Label.Framework.latest.js has been updated to version 1.2.2 as well.

July 27, 2011

DYMO Label Framework JavaScript Library 1.2

Filed under: DYMO Label Framework,News,SDK News — Vladimir @ 7:19 am
Tags: , ,

A new version of DYMO Label Framework JavaScript library is available. This version adds support for Mac OS X 10.7 (Lion).

The js script file is available from http://labelwriter.com/software/dls/sdk/js/DYMO.Label.Framework.1.2.0.js.

The http://labelwriter.com/software/dls/sdk/js/DYMO.Label.Framework.latest.js has been updated to version 1.2.0 as well.

All major browsers are supported: Safari 4-5.1, Firefox 3-5, Chrome, Opera 10. Opera 11 is not supported at the time of writing.

July 20, 2011

DYMO Label Framework JavaScript Library 1.1

Filed under: DYMO Label Framework,News — Vladimir @ 4:40 am
Tags: ,

Update: A subtle bug has been found in the version 1.1.0. It is fixed now and new version 1.1.1 is available.

A new version of DYMO Label Framework JavaScript library is available. This version fixes a problem with setting a label data from Internet Explorer 9. The js script file is available from http://labelwriter.com/software/dls/sdk/js/DYMO.Label.Framework.1.1.1.js

The http://labelwriter.com/software/dls/sdk/js/DYMO.Label.Framework.latest.js has been updated to version 1.1.1 as well.

July 19, 2011

DYMO Label Mobile SDK for Android (Beta)

Filed under: DYMO Label Framework,News,SDK News,SDK Samples — Vladimir @ 8:11 am
Tags: , , ,

We are proud to announce a BETA release of the DYMO Label Mobile SDK for Android. The DYMO Label Mobile SDK for Android is a complete toolset containing libraries, documentation, and samples that make it easy to add label printing to any Android app. All DYMO LabelWriter and DYMO LabelManager printers are supported. Using the DYMO Label Mobile SDK in combination with DYMO Label Web SDK allows creating both native and web-based apps for Android.

Please Note

This release is a BETA. It has not been extensively tested outside DYMO and should be used for developer testing only, NOT for production software releases.

Architecture Overview

It is essentially the same as the architecture of DYMO Label Mobile SDK for iOS.

DYMOLabelMobileSDKforAndroid

The major piece here is a computer that has a DYMO printer plugged-in and DYMO Label software installed. DYMO Label software contains a service called DYMO Label Proxy that allows communication between an Android device and the printer.

Notes:

  • right now DYMO Label Proxy is available for Windows only. So, a printer must be connected to a Windows machine, or be available from Windows machine that has DYMO Label Proxy installed (see below).
  • the printer itself does not have to be connected directly to the computer running DYMO Label Proxy. The printer has to be ACCESSIBLE from that machine. This means that the printer might be really connected to a different machine and be a “shared” network printer. Or the printer might be connected to a DYMO Print Server and be “installed” on the computer using a RAW TCP/IP port. This setup might be used to simplify installation (see below).
  • the local network is used for communications between the proxy service and the mobile device. That means that on the mobile device the Wi-Fi should be turned on and the device should be connected to the network. Using just 3G is not enough.

Installation

SDK Installation

SDK is available here. It is a zip file, just extract it to any folder. Inside there are following folders:

  • docs - SDK documentation. Contains API reference documentation in JavaDoc format.
  • libs - jars to be included with an application.
  • Samples – sample apps.

Samples were tested with Eclipse Helios and Android SDK r11. The SDK supports Android API level 8 (2.2) and later.

DYMO Label Proxy Installation

The installation is fairly simple. Just install DYMO Label software, that’s it. DYMO Label Proxy service will be installed and run as a part of the installation. DYMO Label Proxy is a Windows service running on port 8631 by default. Because of that there are couple of considerations that must be taken into account:

  • DYMO Label Software will configure Windows Firewall to open the port 8631 for inbound requests. If a different firewall software is installed, you have to configure it manually.
  • The port number may be changed from the default one. Either use the configuration utility included or specify the port manually in the service’s application .config file. In any case don’t forget to update the firewall rules to open the port. Otherwise clients will not be able to connect to the service.
  • The final release to the public will add the ability to select the port number and autostart options for the service during installation.

Note: This version of DYMO Label Proxy contains enchantments and bug fixes over the version released for Web and iOS SDKs. To be able to use with Android SDK you must update it to the latest version.

DYMO Label Proxy Configuration

To configure the service use DYMOLabelProxyServiceConfiguration.exe utility. It lets you change the port number the service is listening to as well as stop/start/restart the service. In addition the utility displays a list of urls that might be used to connect to the service.

image_thumb

Changing Port Number

To change the port number enter a new value into “Port Number” field and click “Apply” button. Right now the service is not restarted automatically, so don’t forget to restart it.

Service Control

You can start/stop/restart the service from within the configuration utility. Alternatively the standard “Services” panel of the  “Computer Management” tool can be used.

Service ip-address

Usually the SDK is able to discover the service on the network automatically using Bonjour. But sometimes Bonjour does not work. One common case is when the service and the Android device are on different subnets, e.g. the mobile device is connected to a “wireless” subnet and the service to a “wired” subnet. This is not a problem with the DYMO service, it is how Bonjour works in its default configuration. There are solutions for this problem, but the detailed descriptions are beyond the scope of this post. Some ideas:

In this case it is necessary to know the service’s ip-address to be able to connect to it from the Android device (see below). The configuration utility can help here as well. Service’s ip-address(es) is displayed in Service URIs list.

API Overview

The SDK contains two complete samples those demonstrate most of the functionality the SDK provides. Here we will look at the API from the point of tasks that are necessary to perform to print a label. To print a label the following tasks usually have to be performed:

  1. framework initialization
  2. discover a printer to print the label on
  3. load label layout
  4. set label data
  5. perform actual printing
  6. Monitor printing progress

Note: these tasks might be performed in a different order, e.g. printer discovery might be performed after the label is prepared for the printing. Though usually printer discovery should be performed first, because it can take some time.

Framework Initialization

All SDK classes and interfaces are accessed from a top label Framework object. A constructor of Framework class accept Context as a parameter. The context might be either an activity/service or be the application context. The Framework instance can be created inside activity’s onCreate()  handler. Note, that Framework initialization might take some time; so if the activity ca be frequently recreated or if the Framework should be accessed from different activities, it make sense to use some sort of singleton to make sure only one instance of the Framework exists.

import android.content.Context;
import com.dymo.label.framework.Framework;

class PrintLabelManager
{
    static private PrintLabelManager instance_;

    static PrintLabelManager instance(Context context)
    {
        if (instance_ == null)
            instance_ = new PrintLabelManager(context);

        return instance_;
    }

    private Framework framework_;

    private PrintLabelManager(Context context)
    {
        framework_ = new Framework(context.getApplicationContext());
    }

    Framework getFramework()
    {
        return framework_;
    }
}
import com.dymo.label.framework.Framework;

import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends Activity
{
    private Framework framework_; 

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        setupFramework();
    }

    private void setupFramework()
    {
        framework_ = PrintLabelManager.instance(this).getFramework();
    }
}

 

Discover Printers

Before something can be printed it is necessary to know on which printer it will be printed. Printer discovery is an asynchronous operation. The reason is that it requires network communications and various delays and timeouts might happen during the process. To handle async notifications of the discovering progress a PrintersListener object should be assigned to the Framework object. PrintersListener defines two methods, one called when a new printer or printers are discovered, another when some sort of failure happened. To assign the listener use setPrintersListeners() method. To start discovering call startRefreshPrinters() method. This method is asynchronous and returns almost immediately. When a printer is found the listener’s method newPrintersFound() will be called. The list of available printers can be obtained by the Framework.getPrinters() or by  NewPrintersFoundEvent.getPrinters() methods. If the Proxy service could not be contacted during the discovering, e.g. it went offline, the printerLookupFailure() method will be called. Here is a code snippet to demonstrate that:

public class MainActivity extends Activity
{
    private void setupFramework()
    {
        framework_ = PrintLabelManager.instance(this).getFramework();
        framework_.setPrintersListener(new PrintersListener()
        {
            @Override
            public void printerLookupFailure(PrinterLookupFailureEvent event)
            {
                final String message = String.format("Unable to contact '%s' (%s)", event.getPrinterUri(),
                    event.getLocation());
                Log.e("Print Label", message);

                MainActivity.this.runOnUiThread(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
                    }
                });
            }

            @Override
            public void newPrintersFound(final NewPrintersFoundEvent event)
            {
                runOnUiThread(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        // output all discovered printers to the log
                        Iterable<Printer> printers = event.getPrinters();
                        for (Printer p : printers)
                            Log.i("Print Label", p.getName());
                    }
                });
            }
        });
    }
}

Please note, the listener’s methods are called from a non-UI thread. So, if you need to perform any UI related operations that must be called from the UI thread, don’t forget to use Activity.runOnUiThread() or View.postDelayed() methods.

Unlike iOS API there is no way to automatically determine when printer discovering should be stopped. It is important to stop it manually by calling stopRefreshPrinters()method. If stopRefreshPrinters() is not called this may lead to an extensive battery drain (underneath implementation uses Bonjour, that uses multicast network requests, and the requests use a lot of power). Call stopRefreshPrinters() after a timeout and when the activity is been stopped.

    // refreshes printers and update currently selected one
    private void refreshPrinters()
    {

        framework_.startRefreshPrinters();

        // / stop refreshing in 5 seconds
        labelContentEditText_.postDelayed(new CheckedRunnable()
        {
            @Override
            public void run2()
            {
                Log.i("PrintLabel", "----------- Stopping printers lookup after 5 seconds");
                framework_.stopRefreshPrinters();

                // usually this is called from newPrintersFound() handler
                // newPrintersFound will not be called if all printers are gone 
                updateCurrentPrinter(framework_.getPrinters());
            }
        }, 5000);
    }

 

Load Label Layout

A label layout specifies what will printed on a label. The layout contains ‘label objects’ – text, address, barcode, image, etc. Each object has a ‘reference name’, so the object can be referenced programmatically from the SDK. Usually DYMO Label software is used to create a layout and save it as xml file. Because the layout is serialized as a xml document, the layout can be created or modified using any xml editor or even programmatically. This and that blog posts describe label format in great details. To load label layout use one of Framework.openLabel() methods. Usually we will load the layout from an asset. Something like this:

    Label label = framework_.openLabel(this, "Address.label");

This assumes, that the Android project  has “Address.label” file in the assets folder.

image

Set Label Data

Label Layout can already contain data to be printed, e.g. an address. this might be a case when a label is generated dynamically on the server. But usually we will need to set data programmatically based on user’s input. This can be done using two different methods.

The first method allows printing of one label only. Use Label.setObjectText(String objectName, String objectText) method to set text data of Address, Text, Barcode, and CircularText objects. Use setObjectImage(String objectName, Bitmap image) to set image data for Image objects.

The second method is more universal, and it allows printing multiple labels at once. It is implemented using a “label set” concept. Label set is similar to a recordset, a database table. Label set consist of a set of “label records”. Each label record represents data to be printed on one label. Label record itself is conceptually is a dictionary (associative array), where dictionary keys are label object names, and dictionary values are label object data. To manipulate a label set use LabelSet interface. Use addRecord method to add a record into a label set. To set object data in the record, use LabelSetRecord methods. There are methods to add text and image data similar to ones above. Also, there is way to specify formatted/styled text data where each character or line can have different formatting (font size and style). To create a LabelSet use Framework.createLabelSet() method.

public class MainActivity extends Activity
{
    void printWithLabelSet(Printer printer)
    {
        // open a label
        Label label = framework_.openLabel(this, "Address.label");

        // create a label set
        LabelSet labelSet = framework_.createLabelSet();

        // label #1
        LabelSetRecord record = labelSet.addRecord();
        record.setText("TEXT", "6x7=42");

        //label #2
        record = labelSet.addRecord();
        record.setTextMarkup("TEXT", "font family='Arial' size='36'>6x7=<b>42</b></font>");

        // print label
        label.print(printer, labelSet);
    }
}

Actual Printing

To start printing call Label.print() methods. There are several  overrides, the most generic one is print(Printer printer, PrintParams printParams, LabelSet labelSet)

We have to provide three parameters:

  • printer – printer to print the label on. The printer instance can be obtained from a list of available printers populated during printer discovering process described above. This is the only required parameter, all other can be omitted.
  • printParams – printing parameters, like number of copies, print quality, etc. This parameter can be null, in witch case defaults will be used.
  • labelSet – a label set contains data to be printed. If omitted, the data contained by label instance will be printed.

This method call is asynchronous as well. Right after all necessary data are assembled the method returns. Printing progress monitoring can be done using PrintJob instance returned by the print() method (see below).

Print Progress Monitoring

PrintJob instance returned by the Label.print() call can be used to monitor print progress. Periodically call getStatus() method to retrieve current status information. Note: currently only this “polling” schema is supported; in the future we might add “pushing” data from the printer when it status has changed. getStatus() is an async call as well; when the status data has been retrieved from the printer, the PrintJobListener method statusReceived(PrintJobStatusReceivedEvent event) is called. Here is an example:

public class MainActivity extends Activity
{
    private void printButtonClick()
    {
        try
        {
            //... open label, assemble print data, etc 

            // print with default parameters
            final PrintJob job = label.print(currentPrinter);

            final Runnable getStatus = new CheckedRunnable()
            {
                @Override
                public void run2()
                {
                    job.getStatus();
                }
            };

            // an executor service to ask for the status in the background 
            final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

            // set the listener to be called when the status received
            job.setOnStatusListener(new PrintJobListener()
            {

                @Override
                public void statusReceived(PrintJobStatusReceivedEvent event)
                {
                    try
                    {
                        final PrintJobStatus jobStatus = event.getPrintJobStatus();
                        final JobStatusId statusId = jobStatus.getStatusId();
                        final String statusMessage = jobStatus.getStatusMessage();
                        Log.i("job status", statusMessage);

                        switch (statusId)
                        {
                        case ProcessingError:
                            // bad - unrecoverable printing error, do not ask status again
                            break;

                        case Finished:
                            // done - printing is done, do not ask status again
                            break;

                        default:
                            // OK - printing is in progress, ask the status after one second delay
                            scheduler.schedule(getStatus, 1, TimeUnit.SECONDS);
                            break;
                        }

                    }
                    catch (Exception e)
                    {
                        handleException(e);
                    }
                }
            });

            // schedule first status request in a second
            scheduler.schedule(getStatus, 1, TimeUnit.SECONDS);

        } catch (Exception e)
        {
            handleException(e);
        }
    }
}

Setup an Eclipse Project to Use SDK

Add Jars into a classpath

To use classes from the SDK two jars must be added to a class path (both can be found in the libs folder). The first one is DymoLabelFramework.jar – it contains the SDK classes. The second one is jmdns.jar. It contains Bonjour implementation used for printer discovering. JmDNS is an open source implementation of Bonjour/multicast-DNS for Java. The version bundled with the SDK is JmDNS 3.4.0 and can be downloaded from http://sourceforge.net/projects/jmdns/

Check Android SDK Target Version

The DymoLabelFramework internally uses some classes available only starting from Android SDK API level 8 (Android 2.2, Froyo). Make sure the project targets Android 2.2 or later.

Set Proper Permissions

The SDK requires two permissions to be set in AndroidManifest.xml. The first is android.permission.INTERNET, so the SDK be communicate with the Proxy service. The second is android.permission.CHANGE_WIFI_MULTICAST_STATE that is required to be able to use Bonjour for printer discovering.

Note: samples applications use another one, android.permission.ACCESS_NETWORK_STATE. It is uses to determine Wi-Fi status and ask a user to turn Wi-Fi on if necessary because otherwise no printers can be discovered. It is strictly to be a little bit more user-friendly, and is NOT required.

Setup an Ant Build Script to Use SDK

Use Android SDK tools to generate/update initial build.xml file.

Check Android SDK target version in default.properties file, so target=android-8 (or later).

Specify path where the jars are located in build.properties by using jar.libs.dir  property. E.g. for the sample projects jar.libs.dir=../../libs.

Note: to compile sample projects from the command line you have to specify path to the Android SDK in the local.properties file by using sdk.dir property.

Conclusion

DYMO Label Mobile SDK for Android provides a simple way to add label printing capabilities to any Android app. Along with DYMO Label Web SDK developers can use DYMO printers from their web-based applications or  from native apps.

Next Page »

Theme: Customized Rubric. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 73 other followers