Wednesday, July 13, 2016

Creating QR Codes from ABAP

Recently I've been investigating the technical possibilities of generating and using QR codes in an SAP Netweaver (or CRM On Premise) context. I've learned a few useful things along the way, and I would like to share them here.

What are QR codes again?

QR Codes have been around for quite some time and I think almost everbody has seen at least one QR Code in the last few years. A QR code is basically a two-dimensional barcode that can contain a small amount of information, Typically this will be an identifying number, a url or a small amount of text. The meaning of the content depends on who scans it. A typical generic QR Code app on your smartform will probably assume that you are scanning a url and want to visit that url. In other scneario's you might have a coupon that gives you a discount.

QR Codes were first put to use in logistics, where its greater capacity, faster readability and error correction made it more popular than the traditional 2d barcodes. Think of applications like inventory tracking and QA.

Overhyped? Past the hype?

Then the world changed. One day everybody had a smartphone with camera in their pocket. Somebody came along and found out that you could scan a QR Code with that camera. Suddenly QR codes where everywhere and were used in every marketing campaign, sometimes right and sometimes wrong.

Luckily we're past the hype. You still encounter numerous misplaced QR codes, but they have lost their attention value. Most people will simply ignore them, unless... Unless they actually add value!

I think there are lots of actually useful applications in the area of Customer Engagement:

  • Offering discounts through a coupon or promotion;
  • Unlock exclusive content;
  • Public transport/flight boarding passes;
  • Event registration/attendance registration.

Generating QR codes in SAP

Ok. We've got that out the way. Now we want to create a QR code with ABAP. Up until some time ago, the most mentioned method revolves about calling a Google webservice to actually create the QR Code.

I have some problems with this method because by using it you create a dependency between that service and your solution:

  • You need to be able to connect your Netweaver stack with this service, which is not always possible/allowed;
  • You have to design for failure as the service may be down;
  • It's a free service, so there is no obligation to keep the service up and running. Any day Google can decide to take down the service or declare it deprecated. Oh wait, they already have...

We're in luck, because there is a better way. If you make sure you have a few Basis notes in place, 2030263, 2029589, 2029824, you can use New Barcode Technology to natively generate QR Codes without any external dependancy. (As mentioned in these SCN Threads).

A quick how to:

  • Go to SE73 (SAPScript font maintenance)

  • Choose System Bar Codes, Change
  • Create a new Bar Code (choose New Bar Code Technology) and enter details:

More details on all those settings can be found here.

  • After creating the Bar Code, you can directly test it in SE73 with F6:

  • In order to use the Barcode, create a style in transaction SMARTFORMS:

Then you can use that style in a Smartform:

And there we have a native QR code, made in ABAP:

Oh no!

But wait, now we only get to use it in SAPScript and SmartForms! This can't be right! What if I want to expose my QR code to a UI5/Fiori app using Gateway? Or what if I want to embed the QR code in an email? If only there was a way to convert the SmartForm to an image. We're in luck again, because this has been done already. Thanks for sharing!

I've adapted the code sample a bit to:

  • Output just the bytes stream instead of saving to local disk
  • Convert to PNG format as this leads to a much smaller file size than BMP format. (Also: see report GRAPHICS_IGS_IMGCONV_DEMO)

  " Convert *.BMP format to *.PNG format

  " This will make the two-color image much smaller
  DATA: lo_igs_imgconv TYPE REF TO cl_igs_image_converter.
  CREATE OBJECT lo_igs_imgconv exporting destination = 'IGS_RFC_DEST'.

      blob      = bitmap2
      blob_size = bitmap2_size ).

  lo_igs_imgconv->input  = 'image/x-ms-bmp'.
  lo_igs_imgconv->output = 'image/gif'.

  lo_igs_imgconv->execute( ).

      blob      = bitmap5
      blob_size = bitmap5_size ).

  " Convert table to binary string
  LOOP AT bitmap5 ASSIGNING <bitmap5>.
    CONCATENATE rv_image_data <bitmap5>-line INTO rv_image_data IN BYTE MODE.

Now we can use this method easily to expose the QR Code image any way we want, by simply calling:

data(lv_image) = zcl_qrcode=>get( '123456789' ).

(Download this nugget for complete code)

Going beyond: Apple Wallet?

By generating a QR code as an image we have opened up a lot of possibilities and scenario's to use QR codes. Why not go a bit further and create Apple Wallet passes? Apple Wallet (formerly known as Passbook) is a convenient way for your end user to store tickets, vouchers and cards that would otherwise be printed or stored in emails.

Wallet allows your end user to efficiently keep all passes in one place and present them when needed. And it does not only work on iOS, there are also Android apps that can store Wallet passes!

Unfortunately, creating a real Apple wallet pass from ABAP is well beyond the scope of this blog, so I'll need to save that for some other time. However, I can share my notes:

A passbook pass - or a *.pkpass file - is basically a *.zip file with some special files.

It is possible to create passbook files from iOS apps and OS X apps, but there are also PHP and Java implementations that can generate valid pkpass files.

I've looked at some of these implementations and it should be possible to build them also in ABAP. The biggest hurdle is that the passbook file should be signed with a valid apple developer certificate. This means you will need to:

  • Have an Apple developer account;
  • Need a way to create a digital sigature.

The first is easy, the second can be a bit more challenging. I've looked a bit but I cannot find any Class or Function module that can do this. Maybe someone can point me in right direction?

However, it is also possible to create a valid wallet pass using the openssl command. This means that by crafting some logic around an SM69 command might do the trick. But that is for another day...