Barcodes with iOS: Bringing together the digital and physical worlds (2015)

Chapter 5. Generating barcodes

This chapter covers

·        Producing 2D barcodes for display and print with Core Image

·        Printing sheets of barcodes with AirPrint

·        Saving paper with the AirPrint Printer Simulator

·        Generating 1D barcodes with BarCodeKit

·        Printing to AirPrint roll-feed printers

Half of your world already has barcodes on it. The other half has only been waiting for you to finish this chapter, so that you can remedy the barcode vacuum wherever you might encounter it. This chapter will teach you how to generate barcodes for display and print. With this knowledge under your belt, you’ll be able to extend your scannable barcode universe virtually without limit.

The ability to print barcode stickers was long the domain of large corporations or supermarkets who could afford to buy special printers for this purpose. Nowadays companies like Brother offer label printers that print to inexpensive thermal-paper rolls for less than $100. Those make the physical printing of barcodes attainable for everybody. In turn, Apple added AirPrint support for such label printers in iOS 7. Wireless printing of single stickers from any iOS device is a huge convenience.

For example, users could catalog their personal library and keep track of their books by adding stickers stating, “This book is the property of ...” and a serial number barcode. Another app might let you keep track of the contents of moving boxes—you could keep track of what you put into which box, and then the app would create a manifest listing the boxes and their contents. A barcode sticker affixed to each box would link the box back to the matching manifest.

A whole new world of creative and productive label apps is waiting to be created by iOS developers.

5.1. Producing barcodes for display or print

In chapter 4 you created digital passes that included one of three different kinds of 2D barcodes. In that chapter it was sufficient to include a pass’s content and type in the pkpass JSON file. The barcode shown when presenting the pass was generated on the fly by Passbook via the Core Image framework.

Passbook passes are meant to be scanned off device screens by CCD-based scanners or cameras. The reflectivity of the glass display plays tricks on laser-based scanners, which are still widely used for scanning 1D barcodes. This is the official reason for the lack of 1D barcode support in iOS.

 

Requesting enhancements

Apple is an engineering-driven company with limited engineering resources. If you wish for native support of 1D barcode generation in a future iOS version, please pause right now and file an enhancement request on Apple’s bug reporter website (https://bugreport.apple.com).

If you do file such an enhancement request, mention rdar://14767897 as the original request for 1D barcodes, which will allow the Apple engineer dealing with your request to count it as a vote on the earlier request.

The bug reports and enhancement requests that gather the most votes—a.k.a. dupes—have higher priority when Apple is putting together the feature set for the next major iOS version.

 

To be able to generate 1D barcodes despite the lack of official support, I developed BarCodeKit, a commercial framework that you can use to generate the most common types of 1D barcodes. Readers of this book—as a thank you—receive a free license to use BarCodeKit for their projects.

Printing on iOS happens via AirPrint, which may initially seem somewhat difficult to grasp because of the many options for simplified printing of objects such as images and attributed strings. You’ll learn how to customize the rendering of content for print. Besides traditional sheet-based printers, there are now roll printers that are particularly well suited for printing barcode stickers. We’ll look at printing sheets of QR Code stickers in the first half of this chapter, and individual serial number stickers in the second half.

5.1.1. Thoughts on barcode size

When printing barcodes, you should consider the distance from which people will typically scan them. A 1D serial number sticker would typically be scanned from a short distance. The minimum bar width a printer is able to output sets a lower limit on how small you can print 1D barcodes.

People scanning a QR Code on a poster might be much further away; for example, the poster might be on the other side of the subway tracks. If the QR Code on such a poster is too small, you’ll be putting people’s lives in danger if they have to lean over the tracks to scan the code.

As a rule of thumb for QR Codes, the width of the printed code should be no less than a tenth of the scanning distance for low-complexity codes. The size of the code needs to increase as complexity and error correction increase. For the highest-complexity codes, you want the width to be at least a quarter of the scanning distance. If you put a QR Code with a diameter of 30 centimeters (about 12 inches) into your office window, the maximum distance from which people could scan it is about 3 meters (about 10 feet).

5.1.2. QR Code error correction

QR Codes can have one of four error-correction levels, which determines the level of redundancy spread over the area of the code:

·        L—7%

·        M—15% (iOS default)

·        Q—25%

·        H—30%

The higher the redundancy level, the more a code can be covered or damaged while retaining its scannability.

In figure 5.1 the content on the left was encoded four times with identical scaling factors—only the redundancy level was modified. You can see that the size needed increases with redundancy, and thus complexity.

Figure 5.1. QR Code error-correction levels

 

Barcode Guru Tip

The error-correction level used is indicated in the QR Code by the two squares (referred to as modules) next to the lower-left centering mark, as shown in figure 5.1. Two black modules in this space indicate the lowest level of error correction; if this space is void of modules, that indicates the highest level of error correction. If you commit this to memory, you can impress your friends by being able to tell them which error-correction level was used just by glancing at a code on a poster.

 

Error-correction levels L and M are recommended for general marketing use. Levels Q and H should be preferred in industrial scenarios, where keeping the code clean or undamaged might be a challenge.

For engineers, the error-correction level is a means to increase reliability. For designers, it’s an opportunity for branding. Often you’ll see parts of QR Codes replaced with a company logo or graphics, as in figure 5.2. For this example, which is based on an H-level complexity QR code, I counted off 10 modules from each side toward the center, and placed my photo within that boundary.

Figure 5.2. Adding a personal touch to a marketing QR Code

Other possible customizations include rounding off edges between modules, changing colors, and sprinkling in tiny graphical accessories. As long as there’s sufficient contrast between modules and enough information visible, the code can still be scanned. QR Codes are an astonishingly robust technology to be able to withstand such an onslaught of design.

5.2. Generating 2D barcodes

iOS 7 introduced generators for the three 2D barcode types supported in Passbook. Of these, only the generator for QR Codes is a public API that you can use in App Store apps. The other two—Aztec and PDF417—work just as well, but they’re undocumented and thus considered private. I know this because I emailed the responsible frameworks evangelist at Apple.

But let’s not hang our heads in sadness over this. Of the bunch, QR Codes are by far the most widely used and most versatile. QR Codes can be used to represent any kind of data, but their most prevalent use is for containing a website address.

You probably have a stack of printed business cards that—unfortunately—lack a scannable QR Code with your website address. How much more convenient would it be if recipients of your cards could open your home page by simply scanning your card?

Manually copying a URL from a business card into your browser’s address bar is so last century.

5.2.1. Building a QR Code Builder app

Let’s build an app to fix your business cards. You’ll configure and preview a QR Code for your home page on the iOS device screen. You probably have many business cards that need to be QR-enhanced, so we’ll focus on printing an entire sheet of identical QR Code stickers that you can stick on the blank backs of your cards.

The QR Code Builder app will have the following features:

·        The user can enter a website URL into a text field.

·        The app will generate a QR Code as the characters are input and display a live preview.

·        The user can adjust the error-correction level with a slider.

·        The user can copy the image to the pasteboard with a long-press gesture.

·        The app will print the configured QR Code to a sheet of stickers.

The finished QR Code Builder app will look like figure 5.3.

Figure 5.3. Finished QR Code Builder app with printed output

5.2.2. Introducing Core Image

At their core, images consist of colored pixels. Depending on the color space, they might have different numbers of “channels,” most commonly red, green, blue, and alpha. Usually one byte is used per channel. The size in bytes for such a bitmapped image is calculated as width x height x bytes_per_channel x number_of_channels.

Core Graphics—a.k.a. Quartz—represents such bitmapped images as CGImage instances. The Core Graphics framework is written in pure C, meaning that it’s impossible to use CGImage instances directly with UIKit. Apple created UIImage as an Objective-C wrapper class aroundCGImage to bridge the gap. UIImage instances usually carry a CGImage in their belly that contains the actual image data.

When manipulating images in UIKit or Quartz, you never get the benefit of the GPU. That’s why Apple created Core Image as a framework for manipulating images in real time with the full benefit of hardware acceleration by the graphics processor.

In Core Image you don’t deal with individual pixels but rather with manipulation steps. Each such step, represented by a CIFilter, is a recipe for manipulating images represented by CIImage instances. If you chain multiple manipulation steps, Core Image compiles those down to a single GPU program, called a shader. When you request the final output of such a filter chain, the initial input is loaded on the GPU, the compiled shader is run, and you receive the resulting output. Figure 5.4 shows a CGImage being turned into a CIImage, the chained filters doing their work on that, and a new CGImage being created via a CIContext.

Figure 5.4. Core Image filter chain

CIImage instances can be created from a wide variety of sources. Static images will usually come from CGImage instances. You can also pass CVPixelBuffer instances if you want to handle live video coming from an AVCaptureDevice (see chapter 2).

Most Core Image filters have an inputImage parameter for supplying the source image. One category of Core Image filters—the so-called generators—don’t, because they themselves are able to generate images. Generators can serve as input for other filters, or you can simply poll their output. For example, you can use CIConstantColor-Generator for creating images consisting of a single solid color or CICheckerboardGenerator for creating an image with a checkerboard pattern.

Let’s try out a simple Core Image generator by creating an 8 x 8 checkerboard suitable for display with a UIImageView. Note the use of CIColor for specifying colors and CIVector for specifying an x-y offset. Those are the typical immutable parameter objects used by Core Image. Values are specified as NSNumber objects:

Generators output CIImage instances via their outputImage method. To use one with UIKit, you need to render it into a CGImage by means of a CIContext. As you can see in the preceding example, Core Image doesn’t have any knowledge of the device’s content scale, which would be 2 for Retina displays. Because of this, you need to double the size of the generated image and then specify this scale in the method that makes a UIImage out of the CGImage.

This should give you enough information about the general workings of Core Image generators. You’ll be using the specialized Core Image filters that generate 2D barcodes next.

 

Barcode scanning in Core Image

In iOS 8, Core Image’s CIDetector gained the ability to scan rectangles and QR Codes. Up until iOS 7, it could only be used to detect faces. Core Image is designed to work with static images, so this is more of a novelty than of practical use for barcode scanning. It would be frustrating for users to have to retake pictures until they finally detect a barcode.

 

5.2.3. Project setup for Core Image

Now that you understand the basics of Core Image, let’s take advantage of this knowledge and implement the QR Code Builder app for producing QR Codes.

Start a new Xcode project from the Single View Application template. As you can see in figure 5.5, I named the sample app QRBuilder. Add the CoreImage.framework to the app target’s Link Binary With Libraries build phase, as shown in figure 5.5.

Figure 5.5. Link app with Core Image

To add the corresponding import to the prefix header file and make Core Image available throughout the app, put the following into your QRBuilder-Prefix.pch file:

#ifdef __OBJC__

   #import <UIKit/UIKit.h>

   #import <Foundation/Foundation.h>

   #import <CoreImage/CoreImage.h>

#endif

 

Framework autolinking

The LLVM compiler is able to automatically link most common system frameworks without you having to link or import anything. The Link Frameworks Automatically build setting is enabled by default for new projects.

Any iOS app includes UIKit, and its UIImage.h header references Core Image, so you don’t need to manually import the header. This is also why the autolinking feature can add Core Image for you. Nevertheless, it’s good to know what’s going on behind the scenes and how to include frameworks manually if necessary.

 

For the basic UI of the QR Code Builder app, you’ll need to add the following items to the storyboard, with the standard spacing suggested by Interface Builder:

·        Add a UIImageView sized 160 x 160 points to the top left of the view, and set the view mode to Center. This will display the QR Code preview.

·        Add a UISlider below it. Use the inspector to configure the minimum value as 0, the maximum value as 3, and the current value as 0. This will allow users to set the error-correction level.

·        Add a UITextField below that, and add placeholder text to show that users will enter a URL here. Set the URL keyboard type and disable autocorrection. This is where users will enter the QR Code contents.

Figure 5.6 shows these three UI controls making up the user interface. You can also configure the autolayout constraints so that elements stretch together with the view. All elements are positioned such that, if the keyboard shows, they remain visible.

Figure 5.6. Set up the basic user interface.

Create three outlets in ViewController.h to connect to the three UI elements you just added to the storyboard by Ctrl-dragging them from Interface builder onto the Assistant Editor view showing the view controller’s header file (see figure 5.7). These new outlet properties will allow you to interact with these elements from inside the view controller’s implementation.

Figure 5.7. Ctrl-drag to create and connect outlets.

With the same Ctrl-drag technique, add and connect an IBAction for the slider’s Value Changed action and another IBAction for the text field’s Editing Change action in ViewController.m (see figure 5.8). Those fire every time there’s a change in the slider’s position or text is entered into the text field.

Figure 5.8. Ctrl-drag to create and connect actions.

This concludes the basic app setup. These controls will give you the input values for generating your QR Code.

5.2.4. Generating QR Codes with Core Image

The Core Image generator for producing QR Codes is CIQRCodeGenerator. You create the generator object, set the contents in the inputMessage parameter, and retrieve the CIImage from the outputImage property:

The inputCorrectionLevel parameter specifies the error-correction level for output QR Codes. If you omit this parameter, the generator defaults to the 15% level (M). All the error-correction levels mentioned in section 5.1.2 are available for this parameter.

The CIImage that comes out of the generator is not yet usable with UIKit. It first needs to be rendered and scaled.

Scaling QR Codes

The generator creates an image with a module size of 1 pixel. There’s no parameter to increase the module size coming out of CIQRCodeGenerator, so you need to scale those tiny QR Codes to a more useful size.

A CIImage isn’t a finished image but rather a recipe that’s executed when you render the image into some context. There’s a method to make a UIImage from a CIImage, but if you set this on a UIImageView, you’ll find that it gets blurry as it’s scaled up. iOS gives you no control over the interpolation that happens in the Core Image filter chain.

The best way around this limitation is to render the CIImage into a CGImage of same size first. Then you can scale the resulting CGImage and disable interpolation on the CGContext. The following convenience method does that for you:

Hooking up the interactive controls

The preceding method goes into ViewController.m, together with the code shown next, which updates the QR Code preview on several occasions—when the view is first shown and whenever the slider is moved or the text field contents are changed:

Launch the app now and enter a web address in the text field. If you move the slider from left to right, you’ll see the generator adding additional complexity to the preview image. This is the additional redundancy for the higher error correction.

5.2.5. Copying the QR Code to the pasteboard

Generating and previewing the QR Code is nice, but if you can’t get the code out of the app, it gets old quickly. We’ll add the ability to long-press the preview image to copy it to the device pasteboard. This way the user can configure a QR Code and then copy/paste it into another app.

Create a subclass of UIImageView named DTBarcodeImageView with the following implementation:

In Interface Builder (see figure 5.8), change the class name for the image view to DTBarcodeImageView. No other changes are necessary.

If you push down on the image view (see figure 5.9), the context menu appears, offering a friendly Copy option. Click on it to copy the barcode image to the pasteboard. To verify that this worked, switch to any other app that lets you paste images, such as the Mail app when you begin a new email. Pasting there from the pasteboard should reveal the same barcode you configured in your QR Code Builder app.

Figure 5.9. QR Code Builder app showing Copy menu

At this point, the image copied to the pasteboard is the same as the one displayed in the image view. For some use cases you might find it desirable to put a larger-scale barcode image on the pasteboard. To do this you’d have to hold onto the CIImage coming out of the Core Image generator and then produce a larger-scale image for this purpose. You shouldn’t have any trouble implementing this on your own.

5.2.6. Private APIs for Aztec and PDF417 codes

If you want to be bold and experiment with creating the two private types shown in figure 5.10, you can. You only have to replace CIQRCodeGenerator with CIAztecCode-Generator or CIPDF417BarcodeGenerator in the ViewController.m QRCode view preview update. Remove the inputCorrection parameter, because this isn’t supported for these codes.

Figure 5.10. One public and two private 2D barcode generators

For apps that you plan to put on the App Store, you have to stick to the public CIQRCodeGenerator. Enterprise apps, on the other hand, can make use of these private barcode types because they don’t have to be approved by the app review team.

I have a strong feeling that Apple will make these public as soon as it’s convenient for them. You can help them along with their decision by sending them an enhancement request. If you find a strong use case in an enterprise scenario, be sure to mention this to Apple.

 

Note

In iOS 8, Apple added a Core Image generator for Code 128, CICode128BarcodeGenerator. Until Apple adds documentation for it, you should also consider it a private API.

 

5.2.7. Printing barcodes with AirPrint

Displaying your QR Code on the device’s screen is a nice first step, but printing it on something physical can make it much more useful. This section will show you how to print a grid of QR Codes on a sheet of paper or stickers.

 

No more printer drivers

The big idea behind AirPrint is that it eliminates the need for printer drivers altogether. Any iOS device and any modern Mac are able to print to any AirPrint-enabled printer. Even though the prefix “Air” suggests something wireless, the AirPrint protocol works just as well over an Ethernet connection.

Printer companies are able to license AirPrint for zero cost. There’s no better deal than free, and this is why most printer vendors are adding it to their new models. Often AirPrint can also be added by means of a free firmware update.

Apple maintains a list of all certified printer models in their knowledge base (http://support.apple.com/kb/HT4356). Those models have gone through a testing procedure to ensure that the AirPrint protocol has been implemented correctly.

 

There are two main ways that allow the user to pick a printer and options: UIPrint-InteractionController and UIActivityViewController. The former takes the user straight to the print options. The latter displays the Print button next to other activities like copying or sharing the item over social networks.

If you choose the Print button on an activity view controller, iOS will also present the print options from the print interaction controller. Think of the activity view as an extra option allowing the user to perform other activities besides printing on a selected item.

Of these, UIPrintInteractionController is the simpler view controller—you always use the shared instance you get from the +sharedPrintController method. When you use this controller, you need to specify what to print. There are four ways to do that, as shown in figure 5.11.

Figure 5.11. Four ways to specify what to print

iOS is able to do a good job of representing most common file types on paper. You can simply pass one printItem or an array of printItems to iOS and have the operating system take care of the layout and drawing. Let’s try this first.

With Interface Builder, add a new Print button to the right of the QR Code preview. Connect that to a new print: action in ViewController.m:

You should give AirPrint some hints about what you’re trying to do by specifying properties in a UIPrintInfo object as needed. This enables iOS to select the best paper and optimal color settings for your print job.

5.2.8. Saving trees with the iOS Printer Simulator

Apple provides a Printer Simulator app that prints to PDF, allowing you to test how your code will print without wasting any trees. It’s included in the Hardware IO Tools for Xcode package available on the Apple developer downloads portal (https://developer.apple.com/downloads/index.action). You can launch it via the Xcode > Open Developer Tool > Printer Simulator menu option. As long as the Printer Simulator is running on any Mac in your WiFi network, all the simulated printers will be visible to any simulated or physical iOS device.

Figure 5.12 shows the Printer Simulator app in use. The yellow border you see around printed pages marks the nonprintable area that printers typically have. This example came out somewhat blurry because of the small preview image being scaled up to the page size. In real life you’d send a higher-resolution image or create a custom page renderer, as we’ll do in the next section.

Figure 5.12. Simulated sample app printing to simulated inkjet printer

Various kinds of printers are available for testing printing, as you can see in figure 5.13. You can also “load” different kinds of simulated printing media into the simulated printers by clicking on the Load Paper toolbar button.

Figure 5.13. Simulated media options in iOS Printer Simulator

The simulated label printer in the bottom left of figure 5.13 will be important in the second half of this chapter, where you’ll be printing individual labels. For label printers, the 2” Roll and 4” Roll options simulate endless rolls where the cut length is relevant. The other options simulate precut stickers.

The iOS Printer Simulator is a great tool that lets you try out many different combinations of printers and output media. Nevertheless, I advise you to try printing on a physical printer before you ship an AirPrint-enabled app to the App Store.

5.2.9. Custom drawing with UIPrintPageRenderer

Apple provides several specialized subclasses of UIPrintFormatter for laying out simple text, attributed strings, and views. We won’t be looking at those because our ultimate goal is to print a grid of QR Codes.

To render a sheet of QR Codes, we’ll create a specialized page renderer that determines how many pages there are and how to render each page for a given index. Although UIPrintFormatter is a public API, Apple discourages developers from subclassing UIPrintFormatterthemselves. Instead, you should customize a UIPrintPageRenderer for custom printing. Pages can either be completely custom-drawn or you can specify print formatters to be used if you want to mix custom-drawing with pages containing only text.

There are four relevant rectangles on each page:

·        paperRect always has a (0,0) origin and specifies the media size for the sheet of paper being printed on.

·        printableRect specifies the actual area on the page that the printer is physically able to print on.

·        headerHeight and footerHeight specify the heights of the header and footer respectively. By default, these heights are set to zero, but if you set them to a greater value, their custom drawing methods are called.

Figure 5.14 shows where these rectangles are located on a piece of print media.

Figure 5.14. UIPrintPageRenderer methods and properties

All previously mentioned rectangles are measured in points, and 1 point equals 1/72 of an inch. You can calculate the number of points in a print of a given size by multiplying the print size in inches by 72. If you’re using centimeters, multiply the size in centimeters by 72 and then divide the result by 2.54. Here are two preprocessor macros to simplify the math for you:

#define IN_TO_POINTS(in) in*72.0

#define CM_TO_POINTS(cm) cm*72.0/2.54

For this example, we don’t care about the header or footer so we won’t set a height for either. To further simplify the example, we’ll assume fixed label sizes. You’ll position the labels relative to the paperRect’s origin (top left). You’ll likely need to adjust the following measurements to fit your own sticker sheets:

#define MARGIN_TOP_CM 1.0

#define MARGIN_LEFT_CM 1.0

#define LABEL_WIDTH_CM 1.5

#define LABEL_HEIGHT_CM 1.5

#define MARGIN_AROUND_IMAGE_CM 0.125

With these measurements defined, you can implement the method for drawing the page content in QRCodeSheetRenderer as follows:

You need something to draw, so let’s add an image property to the QRCodeSheet-Renderer header. You can set this image to be repeated on all stickers:

@interface QRCodeSheetRenderer : UIPrintPageRenderer

@property (nonatomic, strong) UIImage *image;

@end

Now you can implement the method for drawing individual labels:

As you can see, there’s nothing out of the ordinary in the drawing code. You’re using the same functions and methods you’ve always used for drawing the contents of custom views. UIPrintPageRenderer takes care of setting up the graphics context to fit the points-based coordinate system on each sheet of print media. You don’t have to learn any new functions for drawing on paper.

Compared to a view’s drawRect:, you can think of the inset printable region as the clipping rectangle. Only what you draw inside of that area will appear on paper. Some printers are able to print photos with no borders, but your code still needs to assume that there will be a margin that can’t be reached by your drawing operations.

5.2.10. AirPrint paper selection

By default, AirPrint selects the paper to be used based on the specified outputType and device locale. If you specified that you’ll be printing photos, the output size defaults to an appropriate small photo size like 4 x 6 inches or A6. The general and grayscale output types default to US-letter or A4 format.

The print interaction controller can have a delegate with a method for inquiring about paper size. Print interaction delegate objects can implement one or more methods of the UIPrintInteractionControllerDelegate protocol. The simplest implementation uses a UIPrintPaperclass method to select an optimal paper from the list of papers the printer provides. The following code snippet informs the print interaction controller that the app would prefer US-letter-sized paper for output. As before, the size is specified in points:

- (UIPrintPaper *)printInteractionController:

          (UIPrintInteractionController *)printInteractionController

                             choosePaper:(NSArray *)papers {

   CGSize requiredSize = CGSizeMake(8.5 * 72, 11 * 72);

   return [UIPrintPaper bestPaperForPageSize:requiredSize

                         withPapersFromArray:papers];

}

Paper and tray selection through AirPrint is opaque to developers. Newly certified printers are required to have paper sensors so that they can accurately report what kind of media they have loaded. Apple’s philosophy with AirPrint is to unburden the user from having to wade through many screens of printer settings. Instead, you—on behalf of the user—make a few assertions about ideal paper size and output type, and AirPrint does the rest.

5.2.11. QR Code Builder app summary

Your QR Code Builder app is now feature-complete, as far as this chapter is concerned. You can configure a QR Code for a web address and then print a sheet of copies.

There are many enhancements you could make to the app, such as encoding a vCard for your business as the code data. You could also implement a view for configuring the positions and sizes of stickers on specific sticker sheets. Such a view would have to be called before showing the print interaction controller, because the print interaction controller triggers the actual printing.

5.3. Generating 1D barcodes

With iOS 7 and 8, Apple only supports the generation of 2D barcodes via Core Image, so I created BarCodeKit to fill this niche until Apple adds 1D barcode generators to the operating system. There’s no shortage of application scenarios where you might want to display or print 1D barcodes. One example I’ve encountered is an app for beer connoisseurs that lets users scan the GTIN barcode on a bottle of beer to track which bottles they have in their collection or have tasted. The app displays the GTIN barcode on the details page for each beer—a crisply rendered barcode looks much nicer than a photo.

Previous sections in this chapter introduced you to AirPrint for getting user-generated content into the physical world. Whereas you’ll generally want to print a larger number of identical QR Codes on a sheet of stickers, 1D barcodes are typically serial numbers or product codes that you’ll want to print one at a time. This makes their production an ideal use case for the new breed of roll-feed printers. They allow you to output a single sticker from the roll without having to waste an entire sheet of stickers.

Label printers have dropped in price to below $100, which makes them an inexpensive convenience to keep around. Some AirPrint-enabled models, like the Brother QL-710W (see figure 5.15), feature built-in WiFi, which makes it easy to hook them into your wireless network for printing from your iOS devices. In this section you’ll learn how to generate 1D barcodes and how to support roll-feed printers over AirPrint.

Figure 5.15. Brother QL-710W WiFi label printer

5.3.1. Building a Serial Number Tag app

Imagine that you have an inventory system—like one you’d find in a corporation’s IT department—where each computer gets a unique serial number. Those inventory numbers let the system keep track of hardware assigned to individual employees and also keep track of issues afflicting particular machines in the corporation’s help-desk software.

The app you’ll build next will produce a single serial number barcode sticker to affix to one machine. You want to implement the following features:

·        Allow the user to enter a numeric serial number into a text field

·        Encode the serial number as a Code 93 barcode

·        Show a preview of the serial number sticker on the screen as you type

·        Print a single sticker on a roll-feed printer over AirPrint

The finished Serial Number Tag app is shown in figure 5.16.

Figure 5.16. Finished Serial Number Tag app with one printed label

5.3.2. Introducing BarCodeKit

When I began to research material for this book, I looked for open source projects that would produce 1D barcodes on iOS. Jeff LaMarche created CocoaBarCodes for OS X, which was last updated in May 2009. Chris Zelenak forked the project and implemented basic support for iOS, mostly by commenting out Mac-specific code. This project was abandoned in January 2013.

This prompted me to start a fresh project. My design goals for BarCodeKit were to build it using modern object-oriented methodologies, use ARC, and make sure it was simple to extend. Three volunteers and I gradually enhanced BarCodeKit to support the most commonly used 1D barcode symbologies. Besides all the 1D barcode types that iOS (italic in this list) can scan, many more are supported:

·        Codabar

·        Code 11

·        Code 39 (plain, modulo 43, full ASCII)

·        Code 93

·        Code 128

·        Facing Identification Mark (FIM)

·        GTIN family: EAN-8, EAN-13, UPC-A, UPC-E, EAN-2, EAN-5

·        Interleaved 2 of 5, ITF-14

·        MSI

·        Pharmacode One Track

·        Standard 2 of 5

The BarCodeKit source is included with the other source code for this book (www.manning.com/BarcodeswithiOS). Open the Xcode project and run the iOS demo (shown in figure 5.17) to try out the various barcode types and settings.

Figure 5.17. BarCodeKit iOS demo app

To the outside world, BarCodeKit is a commercial library that costs €150 to license per developer. But because I want to thank you for reading this book, you get a free license. As long as you own a copy of this book, you may use BarCodeKit in all your apps at no charge.

5.3.3. Adding BarCodeKit to your project

To start on the Serial Number Tag app, create a new iOS app project based on the Single View Application, and name it SerialSticker.

The next step is to add BarCodeKit as a dependency to your project and link in its static library target to make its functionality available to your app. Create a new group to take on external references via File > New Group, and name it Externals. Drag BarCodeKit.xcodeproj from the BarCodeKit folder in the sample code into this group (see figure 5.18).

Figure 5.18. Making BarCodeKit a subproject

When you add a file to a project like this, it won’t ask if you want to add a copy of the file or add a reference to it. The default for project files is to add a reference. Project files often have relative references to other resources and source files, so it wouldn’t make much sense to add a copy of the xcodeproj to your project, because that would break those relative paths. Dropping the project file reference into your project makes it a subproject.

Click on the SerialSticker root in the Xcode project navigator to reveal the targets and build settings in the right pane. In the SerialSticker target, under Build Phases, click on the plus button to reveal possible frameworks and libraries you can link to your app (see figure 5.19). Add the libBarCodeKit.a static library for iOS.

Figure 5.19. Linking with the BarCodeKit library for iOS

When building your app, Xcode checks to see if all dependencies have been built before building the app itself. From this reference to the iOS static library, the build system knows that it needs to build the product of the subproject first. You can easily verify this by building the app now (Cmd-B). In the build log you’ll see that BarCodeKit (iOS) gets built first and the SerialSticker target follows suit (see figure 5.20).

Figure 5.20. Implicit dependency built before app itself

Even though you never explicitly specified that the static library would be needed at link time, it still gets built in time. This is why it’s called an implicit dependency. Xcode infers it. If you wanted to be explicit about this necessity, you could add an explicit dependency in the Target Dependencies build phase, but modern Xcode has made this obsolete.

When linking in static libraries containing Objective-C code, you need to give the linker a hint indicating that. The -ObjC linker flag does that. Most importantly, this flag enables the linker to also load categories from the static library. Without this setting, the linking build phase would fail because in BarCodeKit there’s a category on UIImage. The -ObjC linker flag is added in the app target’s Build Settings tab in the Other Linker Flags line (see figure 5.21).

Figure 5.21. Adding the -ObjC linker flag

You tell Xcode where it can find the BarCodeKit header files by specifying this location in the target’s build settings, on the User Header Search Paths line (see figure 5.22). Select the recursive option so that Xcode will look for headers in this folder and all its subfolders.

Figure 5.22. Specifying the header search path

 

Setting the User Header Search Paths

The User Header Search Paths setting is relative to the location of the app’s project file. In the book’s sample code, you get to it by going up one folder to the samples root and back down one folder into BarCodeKit. Depending on your project setup, the BarCodeKit sources might be in a different location. Adjust the path accordingly.

 

I recommend adding imports for larger framework or library headers to the prefix header file because this speeds up compilation and saves you from having to repeat the import in every class you’re using it from. Put the following in your SerialSticker-Prefix.pch file:

#ifdef __OBJC__

   #import <UIKit/UIKit.h>

   #import <Foundation/Foundation.h>

   #import "BarCodeKit.h"

#endif

After these setup steps are complete, you’re ready to use BarCodeKit functionality to generate 1D barcodes.

5.3.4. Setting up the Serial Number Tag app’s UI

Your Serial Number Tag app needs a UI so that you can enter the serial number in a UITextField, view a preview in a UIImageView, and have a UIButton to push for printing the sticker.

Position those three UI elements in Interface Builder as shown in figure 5.23. Set the image view’s content mode to Center. Set the text field’s placeholder, and change the keyboard to the Number Pad option.

Figure 5.23. Basic UI for the Serial Number Tag app

You need IBOutlets in the ViewController.h header for the field and image views so that you can manipulate them from code. Open the header in Assistant Editor and Ctrl-drag them to the header to make them outlets (see figure 5.24).

Figure 5.24. Connecting Serial Number Tag app outlets

Similarly, Ctrl-drag from the button and text fields (see figure 5.25) into the ViewController.m implementation file to create IBActions. The control event type for the button should be Touch Up Inside. You want to get all changes for the text field, so pick Value Changed.

Figure 5.25. Connecting Serial Number Tag app actions

Do a quick test to see if everything is connected correctly by adding two quick NSLog statements, as follows. The editor will show filled bullets to the left of the method prototypes to indicate the connection:

- (IBAction)print:(UIButton *)sender {

   NSLog(@"Print pushed");

}

- (IBAction)textFieldChanged:(UITextField *)sender {

   NSLog(@"New value: %@", sender.text);

}

If you type in the text field, you should get output after each typed number and a single log entry if you click on the Print button. Now you’re ready to start converting the serial number into a barcode.

5.3.5. Generating 1D barcodes with BarCodeKit

Barcodes in BarCodeKit are all concrete subclasses of BCKCode. With the previous setup out of the way, you can create a Code 93 from the text field’s contents. The following snippets all go into ViewController.m.

Let’s start with a convenience method that gets you the current barcode:

BCKCode doesn’t have a built-in graphical representation because it’s essentially only a string of bars and spaces. To get an image representation, you use a category method on UIImage that takes an optional dictionary of rendering options. The single most important rendering option isBCKCodeDrawingBarScaleOption, which defaults to 1. This is the number of points representing each barcode module.

Now you can add some code to refresh the barcode preview when the view controller loads the first time and whenever something is typed into the text field:

The BCKCodeMaxBarScaleThatFitsCodeInSize convenience function determines the maximum bar scale at which the resulting image will still fit in the specified space. By only using integer values for the bar scale, you ensure that entire pixels are always painted with the bars. Otherwise you’d get anti-aliasing effects, causing the bars to be blurry and possibly even unscannable. This is the same reason you disabled scaling for the preview imageView when setting up the UI in Interface Builder.

At this point you can build and run the sample app. Type in various serial numbers and observe how the preview barcode is updated constantly. You’ll also find that you can enter a limited range of nondigit characters. As explained in chapter 1, Code 93 can represent these characters as well.

5.3.6. AirPrint and roll-feed printers

A single serial number barcode should identify a single machine in our imagined inventory system, and it makes no sense to fill an entire sheet of stickers with copies of a single code, as you did for the QR Code Builder app. Rather, this is the perfect use case for specialized sticker printers.

AirPrint has been supporting roll-feed printers since iOS 7. Two kinds of stickers are supported: endless rolls and die cut. The former needs to get info from you as to where to cut between stickers; the latter usually has paper sensors telling you the correct size of the individual precut labels.

In contrast to the QR Code Builder app, which rendered a whole page of stickers, you’ll implement a page renderer for the Serial Number Tag app that knows how to render a single sticker. Create a new BarCodeStickerRenderer class as a subclass of UIPrintPageRenderer. You’ll need a property to set the barcode instance and a convenience method that will tell you the cut length if it’s an endless label roll:

To determine the cut length, you can use an approach similar to the way you determined the optimal bar scale for the preview:

You’ll call cutLengthForRollWidth: later from the view controller.

Now let’s add the print rendering of the label to complete the BarCodeStickerRenderer class implementation. This print-rendering method will again determine the output size of the barcode because the cutLengthForRollWidth: function will only be called if the printer actually requires it.

Even though you might be returning an integer cut length from cutLengthForRollWidth:, the stepper motor of the label printer might not be able to reach all values for the cutting operation, so the paperRect might have a smaller non-integer value for the width or height. AirPrint reduces the cut-length value to the next smaller reachable value, so you have to round up the value to ensure that you arrive at the same bar scale in the methods shown in the previous and following code snippets:

Here you’re not producing a UIImage first, but are rendering straight to the current context. Barcodes created with BarCodeKit can display caption text below the bars, so you can’t simply disable interpolation. If you did, you’d get ugly artifacts around the caption text when scaling the image instead of it looking crisp.

Internally, AirPrint uses vector-based graphics contexts. By rendering into such a context directly—without a detour via an image—the barcode bars become vector rectangles and the caption text is added as vector glyphs. This produces crisp output regardless of the actual resolution.

You can now wire up everything in ViewController.m:

The -print: method—called when the user taps on the Print button—is virtually identical to the one for producing the QR Code sheets. The only differences are a different job name, the orientation is rotated to landscape, and the BarCodeSticker-Renderer is used instead ofQRCodeSheetRenderer (compare to section 5.2.9).

 

Thermal bleeding

Thermal-label printers employ heat for printing. The heat radiates outward from the area where it’s applied, and as a result, a one-point line will always be slightly wider than one point of white space. This effect is called bleeding.

If you don’t compensate for this effect, small barcodes will become unscannable because the ratio between bars and spaces would be too irregular. BarCodeKit has an option to reduce the width of printed bars: BCKCodeDrawingReduceBleedOption.

 

5.3.7. Serial Number Tag app summary

This completes our second sample app for this chapter, focusing on printing a single 1D barcode to a roll-feed printer. Many usage scenarios become possible when you can output a single label or sticker. The serial-number-barcode scenario happens to fit with the theme of this book, but you can probably imagine several other uses for such barcodes.

BarCodeKit fills the niche of 1D barcode generation until Apple adds such functionality to the iOS SDK, which I hope they’ll do eventually. To learn more about the various kinds of barcodes you can produce with BarCodeKit, please look at the online documentation (https://docs.cocoanetics.com/BarCodeKit/), which also lists the class names of the various barcode symbologies supported.

5.4. Summary

Core Image has fallen behind AV Foundation—covered in chapters 2 and 3—in regard to the number of supported barcode symbologies. This makes the interaction between physical items and mobile users somewhat lopsided. This chapter tried to remedy this situation by emphasizing the ease of barcode generation—in particular, on iOS devices—for display or print.

As more mobile users get used to scanning barcodes, it will increasingly make sense in various scenarios to help users interact with the physical world by attaching barcodes to different items. This chapter helps you fuel this fortuitous circle. What situations can you think of where you could simplify a workflow by adding barcodes?

These are the key barcode-generation takeaways:

·        You can generate a great variety of one-dimensional barcodes with the free BarCodeKit library.

·        Two-dimensional barcode generation is covered by Core Image, particularly QR Codes.

·        Check the Core Image documentation to determine which barcode symbologies are documented. Those are the ones that are App Store–legal. Others might technically exist, but you use them at your own risk or outside of App Store distribution.

·        All printing under iOS, whether to sheets or rolls, is done via AirPrint.

·        Inexpensive roll-feed printers allow you to print individual barcode stickers with a minimum of waste.

·        You can’t specify a specific output medium with AirPrint. Instead, you specify the purpose and target output size, and AirPrint selects the best print medium for you.

·        Custom print layouts let you make the best use of the medium and help you avoid empty borders, such as if your layout is for US-letter size, but your user prints to European A4 paper.

This chapter and the one before it dealt directly with barcodes in iOS to give you an understanding of barcodes in general, how to scan them, and how to produce them. The remaining two chapters of this book will dive into technologies that don’t directly relate to barcodes but that—as you’ll see—are highly relevant to barcode apps: retrieving metadata for scanned barcodes and leveraging information about the situational context of the app user.