Feb 212012
 

We are proud to announce the release of the DYMO LabelWriter/LabelManager SDK 1.4.0 for Linux.

This release adds support for the LabelWriter 3xx series printers. Please check the DYMO SDK for Linux document for a complete list of supported DYMO LabelWriter/LabelManager printers.

The SDK is available from here. The DYMO LabelWriter/LabelManager SDK for Linux page is here

 Posted by at 20:53  Tagged with: ,
Dec 022011
 

We are proud to announce the release of DYMO Label SDK 8.3.1. This release contains updated documentation and samples, especially for the new DYMO Label Framework API. The SDK installer is available from here.

Note: do not forget to install DYMO Label software, it is required to run any application that uses the SDK. For more information see this blog post.

Online documentation:

DYMO Label Framework .NET Reference documentation

DYMO Label JavaScript Library documentation

Jul 192011
 

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 and is not supported by DYMO. 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.

Apr 302011
 

We are proud to announce a BETA release of the DYMO Label Mobile SDK for iOS. The DYMO Label Mobile SDK for iOS is a complete toolset containing libraries, documentation, and samples that make it easy to add label printing to any iOS 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 iOS.

Please Note

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

Architecture Overview

Before going into details let’s first look at the high level architecture for the Mobile SDK to understand how it works. It is similar to the DYMO Web SDK with one difference: instead of using a DYMO Label Javascript library, a native binary library is compiled into an iOS app.

Pasted Graphic 1

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 a iOS 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 two formats:
    • html to be viewed using web browser.
    • com.dymo.label.framework.docset to be integrated with XCode. To install the docset copy it to ~/Library/Developer/Shared/Documentation/DocSets folder.
  • include – header files.
  • lib – static libraries to link with.
  • Samples – sample apps.

Samples were tested in XCode 4.0.2 and XCode 3.2.6 for iOS SDK 3.2 – 4.3.

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.

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 iOS 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 iOS 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 that demonstrate most of the functionality the Framework 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 task usually have to be performed:

  1. discover a printer to print the label on
  2. load label layout
  3. set label data
  4. perform actual printing
  5. 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.

Discover printers

Before something can be printed it is necessary to know on which printer it will be printed. DlfPrinters class is used to perform this task. Printer discovery is an asynchronous operation. The reason is that it requires network communications and various delays and timeouts might happen during the process. So, the Framework follows usual iOS SDK approach, and a delegate object is used to provide a way of receiving async notifications of the discovering progress. The delegate protocol is DlfPrintersDelegate. DlsPrintersDelegate defines two methods, one called when a new printer or printers are discovered, another when some sort of failure happened. So, create an object that implements DlfPrintersDelegate protocol, and initialize DlfPrinters instance by passing the delegate object into initWithDelegate: method. It is possible to reassign the delegate later if necessary using delegate property. To start discovering call refresh method. This method is asynchronous and returns almost immediately. When a printer is found the delegate’s method – printers:(id<IDlfPrinters>)sender didFindPrinters:(NSArray*)printers will be called. Here is a code snippet to demonstrate that:

@interface PrintMeThatLabelAppDelegate :
    NSObject <UIApplicationDelegate, DlfPrintersDelegate>
{
@private
    DlfPrinters* printers_;
}

@end

@implementation PrintMeThatLabelAppDelegate

- (void) applicationDidBecomeActive:(UIApplication*)application
{
    printers_ = [[DlfPrinters alloc] initWithDelegate:self];
    [printers_ refresh];
}

- (void) applicationWillResignActive:(UIApplication*)application
{
    [printers_ release];
}

- (void) printers:(id<IDlfPrinters>)dlfPrinters didFindPrinters:(NSArray*)printers
{
    for (id<IDlfPrinter> printer in printers)
        NSLog(@"%@", printer.name);
}

- (void) printers:(id<IDlfPrinters>)printers didFailWithError:(NSError*)error
{
    NSDictionary* userInfo = error.userInfo;
    NSString* s = [[[NSString alloc] initWithFormat:@"Unable to contact '%@' (%@)",
        [userInfo objectForKey:@"printerUri"],
        [userInfo objectForKey:@"printerLocation"]] autorelease];
    NSLog(@"%@", s);
    UIAlertView* alert = [[[UIAlertView alloc]
        initWithTitle:@"Error"
        message:s delegate:nil
        cancelButtonTitle:@"OK"
        otherButtonTitles:nil] autorelease];
    [alert show];
}

@end

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 [DlfLabel labelWithXml:] method. Usually we will load the layout from a resource file in the app bundle. Something like this:

// obtain a reference to IDlfLabel by loading a label from a file
NSString* labelFile = [[NSBundle mainBundle] pathForResource:@"MyLabel" ofType:@"label"];
NSString* xml = [NSString stringWithContentsOfFile:labelFile encoding:NSUTF8StringEncoding error:NULL];
id<IDlfLabel> label = [DlfLabel labelWithXml:xml];

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 [IDlfLabel setText:forObject:] method to set text data of Address, Text, Barcode, and CircularText objects. Use setImage:forObject: to set image data for Image objects.

The second method is more universal, and 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 DlfLabelSet class. Use addRecord method to add a record into a label set. To set object data in the record, use IDlfLabelSetRecord 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).

void PrintWithLabelSet(id<IDlfPrinter> printer)
{
    // open a label
    NSString* labelFile = [[NSBundle mainBundle] pathForResource:@"TextLabel" ofType:@"label"];
    NSString* xml = [NSString stringWithContentsOfFile:labelFile encoding:NSUTF8StringEncoding error:NULL];
    id<IDlfLabel> label = [DlfLabel labelWithXml:xml];

    // create a builder object to populate label set
    DlfLabelSet* labelSet = [[[DlfLabelSet alloc] init] autorelease];

    // label #1
    id<IDlfLabelSetRecord> record = [labelSet addRecord];
    [record setText:@"6x7=42" forObject:@"TEXT"];

    //label #2
    record = [labelSet addRecord];
    [record setTextMarkup:@"font family='Arial' size='36'>6x7=<b>42</b></font>" forObject:@"TEXT"];

    // print label
    [label printOn:printer withParams:nil labelSet:labelSet printJobDelegate:nil];
}

Actual Printing

To start printing call – (id<IDlfPrintJob>) printOn:(id<IDlfPrinter>) printer withParams:(DlfPrintParams*) params labelSet:(DlfLabelSet*)labelSet printJobDelegate:(id<DlfPrintJobDelegate>)delegate method of IDlfLabel

We have to provide four parameters:

  • printer – printer to print the label on. The printer instance can be extracted from DlfPrinters instance initialized previously. 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.
  • delegate – a delegate object to receive status messages about printing progress. this might be omitted as well, if print progress monitoring is not important.

This method call is asynchronous as well. Right after all necessary data are assembled and printing is started the method returns. Printing progress monitoring can be done using IDlfPrintJob instance returned by the printOn: method (see below).

Print Progress Monitoring

IDlfPrintJob instance returned by printOn:withParams:labelSet:printJobDelegate: 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 as well. getStatus: is async call as well; when status data has retrieved from the printer, the delegate method printJob:(id<IDlfPrintJob>) printJob didGetStatus:(id<IDlfPrintJobStatus>) printJobStatus is called. Here is an example:

@interface PrintMeThatLabelAppDelegate : NSObject <UIApplicationDelegate, DlfPrintersDelegate, DlfPrintJobDelegate>
{
@private
    DlfPrinters* printers_;
    id<IDlfPrinter> currentPrinter_;
}

@end

@implementation PrintMeThatLabelAppDelegate

- (IBAction) printAction:(id)sender
{
    // load label
    NSString* labelFile = [[NSBundle mainBundle] pathForResource:@"MyLabel" ofType:@"label"];
    NSString* labelXml = [NSString stringWithContentsOfFile:labelFile encoding:NSUTF8StringEncoding error:NULL];
    id<IDlfLabel> label = [DlfLabel labelWithXml:labelXml];

    // specify label data
    DlfLabelSet* labelSet = [[DlfLabelSet new] autorelease];
    id<IDlfLabelSetRecord> record = [labelSet addRecord];
    [record setText:@"Hello, World!" forObject:@"TEXT"];
    id<IDlfPrintJob> printJob = [[label printOn:currentPrinter_ withParams:nil labelSet:labelSet printJobDelegate:self]
                                retain];

    // start job monitoring
    [(NSObject*)printJob performSelector:@selector(getStatus) withObject:nil afterDelay:1];
}

- (void) printJob:(id<IDlfPrintJob>) printJob didGetStatus:(id<IDlfPrintJobStatus>) printJobStatus
{
    NSLog(@"got print job status: %@", printJobStatus.statusMessage);

    // check status - if not completed then schedule another run, otherwise done with the print job
    DlfJobStatusId statusId = printJobStatus.statusId;
    if (statusId == kDlfPrintJobStatus_ProcessingError || statusId == kDlfPrintJobStatus_Finished)
        [printJob release];
    else
        [(NSObject*)printJob performSelector:@selector(getStatus) withObject:nil afterDelay:1];
}

@end

Setup XCode Project for Using with the SDK

To be able to use SDK libraries to create iOS app a few steps have to be done.  The main (and the only one at the moment) library in the SDK is a static library libDymoLabelFramework.a located in the lib SDK folder. To be able to compile and link  with the library include path to the headers should be specified, as well as the lib path to the library.

  • add a path to header files. Header files are located in DymoSDK/include/DymoLabelFramework folder. So, add the path to SDK/include into “Header Search Paths” Build Settings of the project. After that the headers can be included into *.h or *.m file by using #import “DymoLabelFramework/DymoLabelFramework.h”. Alternatively the include/DymoLabelFramework folder might be copied into the project source folder.  
  • add path to the location of libDymoLabelFramework.a  (DymoSDK/lib) to the “Library Search Paths”
  • add the library libDymoLabelFramework.a into the project. Add it to “Link Binary  With Libraries” group of “Build Phases” tab.libDymo

Conclusion

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

Apr 052011
 

We are proud to announce a BETA release of the DYMO Label Web SDK. The DYMO Label Web SDK contains enhancements to DYMO Label software and the DYMO Label Framework JavaScript library to allow printing from a web browser running on any modern computing platform. This includes any desktop browser running on Windows, Mac, or Linux; mobile browsers on iPhone, iPod, iPad, Android, BlackBerry and even on Kindle :)

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

Before going into details let first look at the high level architecture for the Web SDK to understand how it works.

For the current SDK the architecture looks like this:

SDK1

So, only PC and Mac are supported. DYMO Label software has to be installed on each machine that uses the JavaScript library.

The architecture for the Web SDK is like this:

SDK2

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 a web browser and the printer. Nothing should be installed on any other computing device that accesses the printer. That is the biggest difference from the current SDK where DYMO Label software must be installed on any client computer that needs label printing functionality.

Notes:

  • right now DYMO Label Proxy is available for Windows only. So, a printer should be connected to a Windows machine, or be available from Windows machine 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 RAW TCP/IP port. This might be used to simplify installation (see below).
  • a local network is used for communications between the proxy service and a 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.
  • browsers that use an internal “proxy” servers to fetch internet content, e.g. Opera Mini, are not supported. The reason? It is impossible to contact “local network” servers like DYMO Label Proxy from such browsers.

Usage Scenarios

The first scenario is printing from a computing device that DYMO Label cannot be installed on. This includes a mobile device like an iPad or Android as well as a desktop PC running e.g. Linux.

The second scenario is to simplify installation on Windows. Before now DYMO Label has to be installed on a PC you wanted to print from. Not any more :) Let say you want to be able to print to a “shared” printer connected to a different machine. E.g. the printer can be connected to a “server” or someone’s workstation in a common location, like a "front desk". In this case DYMO Label has to be installed only on the "server" and nothing should be installed on your local PC, even drivers.

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 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 monitor 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.

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

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 standard “Services” panel of the  “Computer Management" tool can be used.

Service URIs

To be able to access the service, the service’s URI should be known on the mobile device. From a programmatic side it is done by calling a framework function addPrinterUri(); we will look at addPrinterUri() later when analyzing a sample application. But what URI to use? Well, it depends on various of factors, like network configuration, a mobile device type, etc.

Bonjour Name

If your device supports Bonjour protocol, i.e. it is a iPhone or iPad, then most likely you can use the first URI in the list, that has a form http://.local:. Here “.local” represents a default Bonjour domain. Even if Bonjour is supported on the mobile device there might be problem if your mobile device and the service are connected to different subnets, e.g. the mobile device is connected to a “wireless” subnet and the service to a “wired” subnet. It is not a problem with the DYMO service, it is how Bonjour works in default configuration. There are solutions for this problem, but the details descriptions are beyond the scope of this post. Some ideas:

DNS Name

If you have a DNS server running on your network, e.g. the PC running the service is in a domain, then most likely you can use a second URI contains just a PC name, like http://.

IP Address

As the last resort you can specify an ip-address. The configuration utility tries to apply some intelligence here and filters ip-addresses. It will show ip-address for active network interfaces only. It will filter VMWare interfaces as well. So, the URI in this case is like http://:

Changes in DYMO Label Framework JavaScript Library

The goal was to modify API in a such way, so existing web applications that use the library should not require major changes. In many cases the only change that needs to be done to an application is to call dymo.label.framework.addPrinterUri() function to “register” the proxy service’s URI, so the framework knows how to communicate with the printer. Below is a short list of changes.

Checking for the Framework Installation

Previously dymo.label.framework.checkEnvironment() function could be used for checking if the library can be used or not. E.g. it checked if the browser is one of the  supported browsers, is DYMO Label software installed or not, etc. Now, because any browser can be used and DYMO Label software is not required to be installed this function is kind of obsolete. It is still a part of the library but it will return a correct result only if running on Windows or Mac assuming you are going to use a Framework dependent parts of the library (see below).

Framework Dependent Functions

Some functions depend on a browser plugin and DYMO Label software being installed to operate. These functions access a local file system to load a label or an image file. If these functions are called when running on a mobile device  an exception will be thrown. It is a good idea to call checkEnviromnent() first to make sure the functions can be called. The functions are dymo.label.framework.openLabelFile() and dymo.label.framework.loadImageAsPngBase64().

Printer Registration

To be able to communicate with the printer , the library needs to know the DYMO Label Proxy service URI. To “register” a printer with the library, use dymo.label.framework.addPrinterUri() function. To “deregester” a printer use dymo.label.framework.removePrinterUri() function. Multiple printers/proxy services can be registered. To register a different service just call addPrinterUri() with a different URI. To deregister all printers use dymo.label.framework.removeAllPrinterUri() function.

Printing Status Checking

When printing from a desktop it might be not necessary to know the print status because the status can be easily accessed from the spooler UI. When printing from a mobile device it is not so easy. So, we added some functions for monitoring print job progress. dymo.label.framework.printLabel2() and label.print2() can be used to create a print job. An object representing a print job is returned by these calls and can be used to monitor  the job progress by calling printJob.getStatus(). There is an utility function to combine both operations into one. It is dymo.label.framework.printLabelAndPollStatus() (and the correspondent label.printAndPollStatus()). Status checking function can be called for any printer, even if the application is running on Windows and  printer is locally connected printer. Status checking for a printer locally connected to a Mac is not implemented in this BETA release.

Sample

Now the fun part Smile Let see how it works in practice. The sample is http://labelwriter.com/software/dls/sdk/samples/js/PrintMeThatLabel/pl.html. When manually typing the url, make sure to use it as-is, because it is case-sensitive. The JavaScript code for the sample is http://labelwriter.com/software/dls/sdk/samples/js/PrintMeThatLabel/PrintMeThatLabel.js

Adding Printer URI

The first thing that has to be done is to add/register printer URI. Type one of the URIs displayed in the configuration utility into the “Printer location(url) field. Make sure to use the full URI, including the protocol scheme. Then click the “Add” button. A list of printers installed on the proxy’s machine should be displayed in the printers drop down list. The click event handler for the “Add” button is as following:

addPrinterUriButton.onclick = function()
{
    try
    {
        var printerUri = printerUriTextBox.value;
        if (!printerUri)
            throw new Error("Specify printer Url");

        dymo.label.framework.addPrinterUri(printerUri, '',
            function()
            {
                settings.printerUris.push(printerUri);
                saveSettings();
                updatePrinters();
            },
            function()
            {
                alert('Unable to connect to "' + printerUri + '"');
            }
        );

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


It checks that something is entered into printer URI field and then calls dymo.label.framework.addPrinterUri() function that does the main job. The signature for addPrinterUri() is

/**
    @param {string} printerUri
    @param {string=} opt_location
    @param {Function=} opt_successCallback
    @param {Function=} opt_errorCallback

    @return {undefined}
*/
dymo.label.framework.addPrinterUri = function(printerUri, opt_location, opt_successCallback, opt_errorCallback)

addPrinterUri() accepts four parameters:

  • printerUri – string URI of the proxy service. It is a required parameter
  • opt_location – optional string representing the printer location. A value passed in this parameter will be used as a part of printer name. If nothing is passed, then the host part of the URI will be used as the location.
  • opt_successCallback – optional callback function called when the service has returned information about available printers. One parameter is passed to the callback – the printerUri of the service.
  • opt_errorCallback – optional callback called when the service cannot be contacted, e.g. the service is down, or the printerURI is invalid. One parameter is passed to the callback – the printerUri of the service.

When addPrinterUri() is called it remembers the printerUri in an internal structures and tries to make a request to the proxy service to obtain information about available printers – model name, printer name, printer type, etc. This request is made asynchronously, so addPrinterUri() returns almost immediately, and callbacks, if provided, are called later when the request is completed. You know, the usual Ajax stuff Smile

For the sample, the printerUri parameter is taken from the printer url field. The opt_location is an empty string, so the host part of the uri will be used as a location. opt_errorCallback displays a simple message box telling the user about connection problem. opt_successCallback remembers the uri, so next time you opens the sample there is no need to reenter the uri (see below for more discussion). After that a printers drop down list is updated by updatePrinters().

function updatePrinters()
{
    // clear first
    removeChildren(printersComboBox);

    printers = dymo.label.framework.getPrinters();

    for (var i = 0; i < printers.length; i++)
    {
        var printerName = printers[i].name;

        // add combo box item
        var option = document.createElement('option');
        option.value = printerName;
        option.appendChild(document.createTextNode(printerName));
        printersComboBox.appendChild(option);

        // select current printer
        if (printerName == settings.currentPrinterName)
            printersComboBox.selectedIndex = i;
    }

    // hide 'add printer url' controls if there are printers to use
    printerSettingsDiv.style.display= printers.length == 0 ? 'block' : 'none';
};


The main item here is a call to dymo.label.framework.getPrinters(). getPrinters() is a synchronous call that uses “cached” printer information returned by the proxy service. Because it is called from a opt_successCallback we are sure that information is really available. It would be a mistake to call  dymo.label.framework.getPrinters() right after dymo.label.framework.addPrinterUri() like this

// Don't do that, will not work
dymo.label.framework.addPrinterUri('http://myservice:8631');
var printers = dymo.label.framework.getPrinters();
// process printers...

In this case the ‘printers’ variable most likely will contain an empty array (or array with local printers only).

Multiple proxy services can be added/registers at the same time. Just type a new service uri and click “Add” button.

To remove/unregester all proxy services, click on “Clear” button

clearPrinterUriButton.onclick = function()
{
    dymo.label.framework.removeAllPrinterUri();
    settings.printerUris = [];
    saveSettings();
    updatePrinters();
}

dymo.label.framework.removeAllPrinterUri() does the main job and the rest updates the UI.

If you want to unregister one proxy service you can call dymo.label.framework.removePrinterUri() with the service uri as a parameter.

/**
    @param {string} printerUri 
    @return {undefined}
*/
dymo.label.framework.removePrinterUri = function(printerUri)

Settings

An utility Settings class is used to store proxy Uris and the last used printer between sessions. In this sample, cookies are used as a persistent storage. In a real application other more reliable mechanisms should be used instead.

// app settings stored between sessions
var Settings = function()
{
    this.currentPrinterName = "";
    this.printerUris = [];
}

// loads settings
Settings.prototype.load = function()
{
    var currentPrinterName = Cookie.get('currentPrinterName');
    var printerUris = Cookie.get('printerUris');

    if (currentPrinterName)
        this.currentPrinterName = currentPrinterName;

    if (printerUris)
        this.printerUris = printerUris.split('|');
}

Settings.prototype.save = function()
{
    Cookie.set('currentPrinterName', this.currentPrinterName, 24*365);
    Cookie.set('printerUris', this.printerUris.join('|'), 24*365);
}

Loading Labels

DYMO Web SDK supports printing on both die-cut labels and tape labels. Label files for these two labels type are similar but different. So, the sample needs two label files for printing depending upon what printer is selected.

// load labels from the server
function loadLabels()
{
    $.get("Address.label", function(labelXml)
    {
        addressLabel = dymo.label.framework.openLabelXml(labelXml);
    }, "text");

    $.get("12mm.label", function(labelXml)
    {
        tapeLabel = dymo.label.framework.openLabelXml(labelXml);
    }, "text");
}

Labels are fetched from files “Address.label” and “12mm.label”. This  files are located on the server in the same folder as other files for the sample. The files are loaded using jQuery’s get() method. After label files are loaded, they are “opened” by using  dymo.label.framework.openLabelXml() function; the resulting “label” objects are stored in addressLabel variable and tapeLabel variable.

Printing and Status Checking

Type some data into the label text box and click “Print” button. The following is the function that does printing. It is a little bit long, but we will look at it part by part.

printButton.onclick = function()
{
    try
    {
        printButton.disabled = true;

        settings.currentPrinterName = printersComboBox.value;

        var text = document.getElementById('labelTextArea').value;

        var printer = printers[settings.currentPrinterName];
        if (!printer)
            throw new Error("Select printer");

        // determine what label to print based on printer type
        var label = null;
        var objName = "";
        if (printer.printerType == "LabelWriterPrinter")
        {
            label = addressLabel;
            objName = "Address";
        }
        else
        {
            label = tapeLabel;
            objName = "Text";
        }

        if (!label)
            throw new Error("Label is not loaded. Wait until is loaded or reload the page");

        // set data
        var labelSet = new dymo.label.framework.LabelSetBuilder();
        labelSet.addRecord().setText(objName, text);

        // print and get status
        var printJob = label.printAndPollStatus(printer.name, null, labelSet.toString(), function(printJob,
        printJobStatus)
        {
            // output status
            var statusStr = 'Job Status: ' + printJobStatus.statusMessage;

            var result = (printJobStatus.status != dymo.label.framework.PrintJobStatus.ProcessingError
                && printJobStatus.status != dymo.label.framework.PrintJobStatus.Finished);

            // reenable when the job is done (either success or fail)
            printButton.disabled = result;

            setTextContent(jobStatusMessageSpan, statusStr);

            return result;

        }, 1000);

        saveSettings();
    }
    catch(e)
    {
        printButton.disabled = false;
        alert(e.message || e);
    }
}

First, the Print button is disabled during printing, just to make things easier. The printer name and text to print is taken from UI elements and saved in printer and text variables correspondingly. If no printer is selected, e.g. no proxy uri has been added, a error saying “Select printer” is displayed.

Depending on the selected printer type a label to print is selected. Also a label object to put data into is selected.

// determine what label to print based on printer type
var label = null;
var objName = "";
if (printer.printerType == "LabelWriterPrinter")
{
    label = addressLabel;
    objName = "Address";
}
else
{
    label = tapeLabel;
    objName = "Text";
}


Then data to be printed is put into a label set object. Usually label sets are used to print multiple labels, but it is perfectly fine to use them to print a single label as well.  In this case the same objects are used regardless of number of labels printed, so the code is easier to adjust.

// set data
var labelSet = new dymo.label.framework.LabelSetBuilder();
labelSet.addRecord().setText(objName, text);


And finally the actual printing

// print and get status
var printJob = label.printAndPollStatus(printer.name, null, labelSet.toString(), function(printJob, printJobStatus)
{
    // output status
    var statusStr = 'Job Status: ' + printJobStatus.statusMessage;

    var result = (printJobStatus.status != dymo.label.framework.PrintJobStatus.ProcessingError
        && printJobStatus.status != dymo.label.framework.PrintJobStatus.Finished);

    // reenable when the job is done (either success or fail)
    printButton.disabled = result;

    setTextContent(jobStatusMessageSpan, statusStr);

    return result;

}, 1000);


The  job is done by the printAndPollStatus() method. This method sends a label and label data to be printed to the selected proxy service, and then periodically checks for the print job status. When a status is available a callback is called with new status information, so the application code can update the UI. printAndPollstatus() has following signature:

/** Prints a label and runs status checking in a loop

    @param {string} printerName
    @param {string} printParamsXml
    @param {string} labelSetXml 
    @param {function(PrintJob, PrintJobStatusInfo): boolean} statusCallback
    @param {number} pollInterval 
    @return {PrintJob}
*/
printAndPollStatus = function(printerName, printParamsXml, labelSetXml, statusCallback, pollInterval)

‘printerName’ is the name of the printer to print on. Usually obtained by calling dymo.label.framework.getPrinters(). printParamsXml – printing parameters, in our case we pass null, so default parameters are used. ‘labelSetXml’ – label data to print. ‘pollInterval’ – interval in milliseconds to ask the proxy service for the job status information. In our case we use an one second interval. ‘statusCallback’ – status callback function called when the service returned status information. the callback takes two parameters; the first is PrintJob object. It can be used to get the status information on demand, without using polling. Also, it might be extended in the future to provide more control over the print job, e.g. an ability to cancel it. The second parameter to the callback is PrintJobStatusInfo class. PrintJobStatusInfo has two properties: statusMessage that contains a status message string; and status that contains status code. The callback has to return a boolean value. If true is returned, than pritnAndPollStatus() will poll the serivce again after the pollInterval passed. If false is returned, then printAndPollStatus() finishes processing. printandPollstatus() returns PrintJob object for the created print job. It has a little of use right now, but may be useful in the future if PrintJob is extended to support more operations.

So, in our sample the callback does the following:

  • a string representing the printing status is assembled by using ‘Job status:’ prefix followed by real status string obtained from statusMessage property.
  • determine if we should continue polling the service for the status or not. We stop polling the service when the status is either dymo.label.framework.PrintJobStatus.ProcessingError, that means something really bad happened and print job has not been even created (e.g. the label has an invalid format, or Windows spooler is not running , or DYMO Label is not installed correctly); or the status is dymo.label.framework.PrintJobStatus.Finished, that means the print job is completed.
  • If no more polling is going to be done, then the “Print” button is enabled again, so another label can be printed
  • and finally the UI is updated to display the status string

The library provides different functions to do printing and status checking. For printing use print2() method of Label object. It has the same parameters as the print() method and returns a PrintJob object. The PrintJob object then can be used to get the status by calling getStatus() method, which has following signature:

/** 
    Gets a status of the print job
    @param {function(PrintJobStatusInfo)} replyCallback a function called when the status is available
    @return {undefined}
*/
getStatus = function(replyCallback)

In addition to Label class methods, similar functions are defined in dymo.label.framework namespace.

One similar to label.print2()

/** Prints a label and returns a print job object

    @param {string} printerName the printer to print on. A list of printers can be obtained by getPrinters()
    @param {string} printParamsXml printing parameters, like number of copies, print quality, etc. See PrintParams.xsd
    @param {string} labelXml label to print
    @param {string} labelSetXml 
        LabelSet to print. LabelSet is used to print multiple labels with same layout but different data, e.g. multiple 
        addresses. 
        Use LabelSetBuilder to create a LabelSet or construct xml manualy according to LabelSet.xsd
    @return {dymo.label.framework.PrintJob} print job
*/
dymo.label.framework.printLabel2 = function(printerName, printParamsXml, labelXml, labelSetXml)


Another, similar to label.printAndPollStatus()

/** Prints a label and runs status checking in a loop

    @param {string} printerName the printer to print on. A list of printers can be obtained by getPrinters()
    @param {string} printParamsXml printing parameters, like number of copies, print quality, etc. See PrintParams.xsd
    @param {string} labelXml label to print
    @param {string} labelSetXml 
        LabelSet to print. LabelSet is used to print multiple labels with same layout but different data, e.g. multiple 
        addresses. 
        Use LabelSetBuilder to create a LabelSet or construct xml manualy according to LabelSet.xsd
    @param {function(PrintJob, PrintJobStatusInfo): boolean} statusCallback
        Function to be called when a print job status is available.
        To continue polling the status the function should return true, false otherwise 
    @param {number} pollInterval poll interval in milliseconds
    @return {dymo.label.framework.PrintJob}
*/
dymo.label.framework.printLabelAndPollStatus = function(printerName, printParamsXml, labelXml, labelSetXml,
statusCallback, pollInterval)

Conclusion

We are really exited about the Web SDK and hope you can find it useful. Any thoughts, feedback, critics are welcome Smile

Jun 022010
 

DYMO has just released a beta version of DYMO Label Framework – a new set of APIs to work with DYMO LabelWriter and LabelMANAGER printers. In this post we will briefly look at different parts of the Framework.

Installation

All needed libraries and binaries are installed by DYMO Label v.8 installer. On Windows you will need to install version 8.2.3.1026 or later available on http://download.dymo.com/download/Win/DLS8Setup.8.3.1.1332.exe http://www.labelwriter.com/software/dls/win/DLS8Setup.8.2.3.1026-BETA.exe. Note: THIS IS A BETA VERSION for developers only. Please don’t install it on customer’s machines.  On Mac DYMO Label version 8.2.2.1173 or later should be installed. It is available on http://www.labelwriter.com/software/dls/mac/DLS8Setup.8.2.2.1173.dmg. Documentation and samples are installed by DYMO Label SDK installer available on http://www.labelwriter.com/software/dls/win/DYMO_Label_v.8_SDK_Installer.exe.

APIs

The Framework supports the following environments: .NET, COM, and JavaScript. The .NET and COM APIs are similar to high-level and low-level SDK APIs in the current API. JavaScript is a new API to be used from a web-browser.

.NET

The Framework itself is almost completely written in C#, so .NET is “natively” supported. To start using it just reference DYMO.Label.Framework assembly. Below is a simple example shows how to print an address label.

var label = DYMO.Label.Framework.Label.Open(@“c:Address.label”);
label.SetObjectText(“Address”, “DYMOn828 San Pablo AvenAlbany CA 94706”);
label.Print(“DYMO LabelWriter 450 Turbo”);

A compete C# sample is available on DYMO Label Framework/samples/C# Sample subfolder of the SDK installation folder. A VB.NET sample is available on DYMO Label Framework/samples/VB Sample subfolder.

COM

Thanks to .NET-to-COM-interop, Framework can be used from any language/platform that supports COM, e.g. Visual C++, Delphi, or VB6. The API is similar to the .NET one. E.G. the above example in C++ will look like this:

#import “DYMOLabelFramework.tlb”
using namespace DYMO_Label_Framework;
IFrameworkPtr framework (__uuidof(Framework));
ILabelPtr label = framework->OpenLabel(L“c:\Address.label”);
label->SetObjectText(L”Address”, L“DYMOn828 San Pablo AvenAlbany CA 94706”);
IPrintParamsPtr printParams = abelWriterPrintParams(__uuidof(LabelWriterPrintParams));
label->Print(framework->GetPrinterByName(L”DYMO LabelWriter 450 Turbo”), printParams); 

JavaScript

Prior to the the introduction of the Framework API DYMO had limited support for accessing printers from web-browsers. Although major browsers (IE, Firefox, Safari on Mac) were supported, the burden of browsers’ incompatibility was on the developers side. That has changed now. Not only more browsers are supported now (IE, IE 64-bit, Firefox, Chrome, Opera, Safari on Windows, Safari on Mac) but the Framework provides a cross-browser and cross-platform pure JavaScript API. The above samples will look like this (in any supported browser):

$.get(http://myserver.com/Address.label, function(labelXml)
{
    var label = dymo.label.framework.openLabelXml(labelXml);
    label.setObjectText(“Address”, “DYMOn828 San Pablo AvenAlbany CA 94706”);
    label.print(“DYMO LabelWriter 450 Turbo”);
});

Note 1: using of jQuery library ($.get function) is just for this sample only. The Framework JavaScript library itself does not have dependencies on any other libraries.

Conclusion

DYMO Label Framework allows easy label printing in many different environments. The APIs provided by the Framework will be explored in more detail in upcoming posts.

May 252010
 

Update: DYMO Label software 8.3 has been released. See http://developers.dymo.com/2011/01/13/announcing-dymo-label-8-3/

Update 2: DYMO Label SDK 8.3.1 has been released. See http://developers.dymo.com/2011/12/02/announcing-dymo-label-sdk-8-3-1/

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.

What’s New

64-bit Support

Now you can use the SDK from 64-bit processes, e.g. Internet Explorer 64-bit. The only thing to do is to recompile your application to be 64-bit, no need to change any code.

New DYMO Label Framework API

Starting this introduces a new API – the DYMO Label Framework. It provides a simpler streamlined interface for printing labels.

Major Features

  • Support for 32-bit and 64-bit applications.
  • Support for Tape printers. Now you can use the same simple API to print on Tape printers as for printing on LabelWriter printers. All you need to do is to design a Tape label in DLS, load it in your application and print.
  • Native .NET support. The Framework provides native .NET support. There is no need to use COM-Interop anymore. Features available in .NET such as indexed properties, enumerators, etc are used to provide an API that is easier to use.
  • COM support. Microsoft COM is supported as well, similar to current SDK.
  • Consolidated High and Low Level API. The Framework combines the current high-level and low-level APIs into a single API. Now there is no need to switch between APIs if you need some advanced functionality not available in high-level API.
  • Cross-browser and cross-platform JavaScript library – see below.

DYMO Label Framework JavaScript Library

To simplify using DYMO Label SDK from web-based application we created a JavaScript library that abstracts browser and platform details for accessing DLS SDK from JavaScript. Now you can use the same JavaScript code to add printing support for any browser the SDK supports. Currently supported browsers are:

  • On Windows: Internet Explorer 6+, Firefox 2+, Chrome 4, Opera 10, Safari
  • On Mac: Safari 3+

Major Features

  • Simple cross-browser and cross-platform API
  • Ability to load and print a label from: a web server, the local file system, or construct on the fly in JavaScript
  • Ability to load images from the server or from local file system
  • Ability to print multiple labels at once

Samples are available on “DYMO Label Framework/Samples/JavaScript” subfolder of the root SDK installation folder. Extensive documentation is provided at the top of the DYMO.Label.Framework.js file.

SDK Installation

The SDK libraries are installed by the DYMO Label 8.2.3 installer. It installs BOTH the DLS SDK (32 and 64 bit) and the new DYMO Label Framework along with drivers and the DYMO Label application.

Windows DYMO Label v.8 Installer

http://www.labelwriter.com/software/dls/win/DLS8Setup.8.2.3.1026-BETA.exe

http://download.dymo.com/download/Win/DLS8Setup.8.3.1.1332.exe

SDK Installer (Documentation and Samples)

http://www.labelwriter.com/software/dls/win/DYMO_Label_v.8_SDK_Installer.8.2.3.123-BETA.exe

http://www.labelwriter.com/software/dls/win/DYMO_Label_v.8_SDK_Installer.exe

Apr 032010
 

So you’ve read somewhere that DYMO LabelWriter printers come with a software developer’s kit, commonly referred to as the DLS SDK. But you might be wondering how DLS SDK can help you and how much time you have to spend learning this SDK before you can start using it. Hopefully this blog entry gives you an idea on how easy it is to get started and also help answer some commonly asked questions by developers.

Before we get too far, let me first explain what the DLS SDK is: it is a programming interface designed specifically for label printing. Using the programming interface (API), one can build a label printing application with minimum amount of work.

Create a label printing application

The following section walks you through the steps of creating a label printing application using the DLS SDK. At the end of the section, you should have an understanding of the basic concepts and the working parts of the DLS SDK.

Step 1. Get the tools you need.

  1. The latest DLS 8 Installer (build 996). It’s important to install the latest version.
  2. The latest DLS SDK Samples. The samples installers installs documentation and technical references to the DLS SDK along with samples to give you an idea of the types of application you can create using the SDK.
  3. Visual Studio 2005 or 2008. I will be using VS2008, but what I do there can easily be done in VS2005.
  4. A PC with a LabelWriter printer connected to it and the latest DLS 8 software installed.

Step 2. Understanding the basic concepts in the DLS SDK

  1. Label File: A label file is a document that contains address, text, barcode, and/or images that you want to print on a label. You can perform various operations on a label file, like Open, Print, SaveAs, etc.
  2. Label Objects: The address, text, and barcode data that are stored inside a label file are logically separated into different label objects. Each object has its own set of properties that control how the object is printed on the label, and the DLS SDK provides access to programmatically create label objects and change label object properties.
  3. Data: The data is a general term for data (i.e. text, address, or image) that you would like to print on a label. The data source can be from user input, a file, or a database.

The DLS SDK ties these three concepts together to enable you to start printing labels in your application with a few lines of code.

Step 3. Defining your application.

To keep the blog short, I will define a simple application that lets users type in a list of to-dos for the day, and print out the list on a label to take with them for the day.

Step 4. Designing a label the application will print (download it here).

  1. start DLS 8, select a shipping label, then change the label orientation to portrait
  2. add a date-time label object on the label
  3. add a text object as header on the label
  4. add a text object as the area to list to-do’s on the label
  5. name the to-do’s text object “todos”
  6. save the label

This video shows you the steps to create the above label.

Step 5. Create an SDK application project in VS2008 (download it here). The important things to note are:

  • make sure the project is targeted for x86 platform. The reason is because the current DSL SDK works only in 32-bit mode (i.e. x86), so if your application is targeted for x64 or AnyCPU, you will not be able to use the DLS SDK.
  • Add a reference to the “DLS 7 Compatibility COM Type Library” in the project. Doing so allows you to use the COM objects that are available in the DLS SDK.

This video shows you the steps to setup the above project.

Step 6. Adding code to take in a list of to-do items from the user, then printing it on label (see listing below).

DymoAddinClass and DymoLabelsClass are the two main objects available from the High-Level COM interface in the DLS SDK. Combined, they provide methods and properties for you to open a label file, set data on label objects in the label file, and print the label. Keep in mind that the DLS SDK is much more extensive than just these two objects, and we will take time to explore them in future blog entries.

1 private void printBtn_Click(object sender, EventArgs e)
2 {
3     DymoAddInClass _dymoAddin = new DymoAddInClass();
4     DymoLabelsClass _dymoLabel = new DymoLabelsClass();
5 
6     // open the to-do-list label we created earlier
7     if (_dymoAddin.Open(@"......To-Do's List.label"))
8     {
9         // this call returns a list of objects on the label
10         string[] objNames = _dymoLabel.GetObjectNames(false).Split(new Char [] {'|'});
11 
12         // verify that our text object is on the label
13         if (objNames.Contains("todos"))
14         {
15             // take the to-do's list entered by the user
16             // and put in on the label
17             if (_dymoLabel.SetField("todos", todoEdit.Text))
18             {
19                 // let's print to the first LabelWriter available
20                 // on the pc, if the printer is a TwiTurbo, print
21                 // to the left tray
22                 string[] printers = _dymoAddin.GetDymoPrinters().Split(new char[] { '|' });
23                 if (printers.Count() > 0)
24                 {
25                     if (_dymoAddin.SelectPrinter(printers[0]))
26                     {
27                         if (_dymoAddin.IsTwinTurboPrinter(printers[0]))
28                         {
29                             _dymoAddin.Print2(1, false, 0);
30                         }
31                         else
32                         {
33                             _dymoAddin.Print(1, false);
34                         }
35                     }
36                 }
37             }
38         }
39     }
40 }
41 
(you can download the complete project here).

Done! As you can see, it didn’t take much to create a simple application that prints labels using the DLS SDK