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.

  32 Responses to “DYMO Label Mobile SDK for iOS (Beta)”

  1. Is the Label Proxy Service available for Mac OS X? The diagram seems to indicate that is it, but the download says differently.
    Please clarify. Thanks.

  2. This is great. Thanks for the SDK. Any update on the next beta or when version 1.0 might come out?

    Thanks.

  3. Thanks for the SDK. Seems to work well but we get a low memory warning (followed by the OS killing our app) when we print and use:

    [record setImage:forObject:]

    or

    [label setImage:forObject:].

    Looking at the low memory crash logs it looks like the app uses a lot more memory when we print images. The printing does actually occur, but things go down hill afterward. Any ideas?

    • If anyone else has trouble with this, make sure you’re passing a grayscale image. We did something like:

      UIGraphicsBeginImageContextWithOptions(visitorPhoto.size, YES, 1.0);
      CGRect imageRect = CGRectMake(0, 0, visitorPhoto.size.width, visitorPhoto.size.height);
      [visitorPhoto drawInRect:imageRect blendMode:kCGBlendModeLuminosity alpha:1.0];
      visitorPhoto = UIGraphicsGetImageFromCurrentImageContext();
      UIGraphicsEndImageContext();

    • Hi Amro,

      Thanks for the comment. The problem might be with the large image size. The SDK does not do anything with the image you passed to setImage() methods. So, if you pass an image taken by the phone camera, the all 5MP (or so) are saved, converted into base64 format, and finally printed. So, the internal size of the label is huge. In this case try to scale down the image, probable depending on the size of the image object on the label. E.g. if the image object size is about one inch, then you can scale the image to 300 pixels (the printer’s dpi is 300). iOS SDK does not have easy usable scaling APIs, you can find one on http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/. The example of using it you can find in the SDK sample VisitorManagemen/MainViewController.m:,

      - (void) imagePickerController: (UIImagePickerController *) picker didFinishPickingMediaWithInfo: (NSDictionary *) info 
      {
          
          NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType];
          UIImage *originalImage, *editedImage, *imageToSave;
          
          // Handle a still image capture
          if (CFStringCompare ((CFStringRef) mediaType, kUTTypeImage, 0) == kCFCompareEqualTo) 
          {
              editedImage = (UIImage *) [info objectForKey:UIImagePickerControllerEditedImage];
              originalImage = (UIImage *) [info objectForKey:UIImagePickerControllerOriginalImage];
              
              if (editedImage)
                  imageToSave = editedImage;
              else
                  imageToSave = originalImage;
              
              // adjust image orientation and size
              imageToSave = [imageToSave thumbnailImage:300 transparentBorder:0 cornerRadius:0 interpolationQuality:kCGInterpolationHigh];
      
              
              // Save the new image (original or edited) to the Camera Roll
              //UIImageWriteToSavedPhotosAlbum (imageToSave, nil, nil , nil);
              self.photoImageView.image = imageToSave;
          }
          
          [[picker parentViewController] dismissModalViewControllerAnimated: YES];
          [picker release];
      }
      
      • Thanks Vladimir. Our image was only 640×480 since it came from the front camera on an iPad 2. We did scale it using [UIImage imageWithCGImage:scale:orientation:], which worked fine in our testing.

        Something like:
        UIImage *visitorPhoto = [UIImage imageWithCGImage:[[UIImage imageWithData:imgData] CGImage] scale:4.0f orientation:UIImageOrientationUp];

        For whatever reason that alone didn’t help. Weird. Anyway, it works now so we’re quite pleased. We’re using it for an interesting internal project.

  4. I am trying to print labels using DYMO iOS SDK. The Static text that I put on the labels prints dark and clean. But any dynamic text prints faded and light. Making the fonts bold for dynamic text in the XML does not help. How can I make dynamic text darker

  5. […] but it was a hack.In his final attempt at doing something a little more sane, Drew stumbled upon a blog post about an iOS SDK (which is essentially a library you can use on an iPhone or iPad to send jobs to a DYMO), that was […]

  6. Hi. Is there ever gonna be a Proxy Service for Linux? It would be really convenient.

    And where do we send our feedback?

    Thanks!

  7. Are there any news about the final release date?

  8. I’m a bit confused. I’m attempting to make use of the Dymo LabelWriter 450 which is connected to my iMac. I can use the Mac version of the Dymo Label software that came with the printer to create labels and print them. I’m developing an iPad app that needs to print labels. In Xcode I use the UIGraphicsBeginPDFContextToData(labelData, CGRectZero, nil); and related functions to then pass the NSData object that is created to a UIPrintInteractionController. A label advances as if it had printed but there is nothing on it. This happens through the simulator with an app running on my Mac that makes the printers connected to the Mac visible to AirPrint.

    So, am I to understand that the only way to print a label on the Dymo printer is to have a proxy service running on a Windows computer? If the Dymo Mac software can print right to the printer without a Windows proxy, why doesn’t the sdk print to it?

    • The LabelWriter/LabelManager SDK for Mac provides everything you need to create and print a label on an DYMO LabelWriter or LabelManager label printer from within your Mac application. More information can be found here http://sites.dymo.com/DeveloperProgram/Pages/LW_SDK_Mac.aspx

      The 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. The DYMO Label Mobile SDK requires a DYMO Label Proxy which is currently available for Windows only.

    • FWIW, I print to a 450 via Printopia in an iPhone app by creating my own UIPrintPageRenderer and implementing – (void)drawPageAtIndex:(NSInteger)index inRect:(CGRect)rect. This does not require any iOS SDKs, just an airprint printer, which Printopia provides/proxies on a Mac. Printopia is important (for me) in that it provides a way to provide the label size to the app which other airprint proxies I looked at did not do. (See https://help.snapsly.com/entries/21186296 for my instructions for my app users on Printopia setup).

      This works well for me when trying to print something I already have in a UIView. Not sure about other variants, e.g., PDF.

  9. it’s not working on Windows 7.
    it says:
    Unable to contact ‘http://My-pc.local:8631’ (My-pc.local)
    even on your test app.
    we ordered about 200 dymo 450 turbos. please help, need to make it work.
    Thanks
    Spasibo

  10. I am trying to add label printing to from a custom iOS app and came across this. However it does not look like this has been updated in a long time and I am having a hard time even getting the samples to work. I can not find the DYMOLabelProxyServiceConfiguration.exe utility in order to get the iOS sample app to locate the 400 Turbo I have setup. It looks like this has been removed from the install and now I can only find DymoPNPService… Any help in getting a sample up and running so I can work off of that would be great.

  11. Hello,
    Any updates on this ? Are you planning on releasing it and get out of Beta ?
    Thanks
    S.

    • We are currently working on our project road map and no date has currently been set to move the iOS SDK into production. However, you are free to use the beta SDK in your applications.

  12. Has there been any updates to this project, how can I use this library with 64bit. Apple now only supports 64 bit in app store and we have around 200 printers that will be useless if we can not push to app store with dymo. Can we get a recompiled sdk for 64 bit

    • No, there hasn’t been any updates to this project. Unfortunately 64-bit code can’t call 32-bit code and vice versa. Currently we don’t have any plans to do any work on iOS SDK (beta).

      • If the iOS SDK is no longer being developed, how about putting the source code on Github so that the community can improve and make it 64-bit ready?

        • The iOS SDK is embedded in DLS and can’t be extracted easily. Furthermore DLS isn’t a open source project and DLS is still being developed. The 64bit support for iOS SDK might be added later.

  13. I am trying to add support for the DYMO LabelWriter Wireless to our iOS app. This is the only SDK I have found on your site. I see you have an iOS app that can print to it, will the SDK be available sometime soon?

    • Hi Peter,

      We have on our long term plan the addition of an iOS (and Android) SDK. Unfortunately, there is nothing available at this time. You could create a proxy service on a Windows/Mac device for printing, if that works.

      Ron

Leave a Reply to Jesse Cancel reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)