A few weeks ago, we started this new blog series focused on the new development tools for ZC1/300. In this new blog, we added complexity to the use case presented in the previous blog, and we show how to optimize the usage of the new ribbons by adding color image and overlay protection/security layers to the cards.

 

The blog series will be covering the following use cases:

  1. ) Android App to print one-sided card through TCP/USB
  2. ) Android App to print double-sided card with 3 layers through TCP/USB
  3. ) Android App to print double-sided card with 3 layers through TCP/USB, but with templates (Future Post)
  4. ) C# App to print one-sided card and to encode with Elatec encoder (Future Post)

 

 

This blog covers the second use case, Android App to print double-sided card with 3 layers through TCP/USB. The blog series is inspired by a Print DNA DEVKITCHEN workshop conducted in Bogota, Colombia this past August.

 

 

Card Printers normally use ribbons to print on the PVC cards. The ribbons are designed with multiple panels. The example below is normally called a YMCKO ribbon.

 

The image above specifies a common type of ribbon for card printers. For printing a basic layer of a color image, the printer will be using three panels YMC. The “O” overlay panel provides an extra protection from tampering, but sometimes the overlay is used for adding visual effects allowing images printed on it. The “K” panel is designed specifically to print barcodes that easily can be read through scanners, although you can implement this for additional monochromatic uses.

 

 

For the exercise presented in this post, we will be adding a basic color image layer with the first picture captured with the app. Then we'll add a second layer within the second picture captured by the app. The second image will be printed on the overlay for the front side of the card. The concept is shown in the picture below with the text “TEXT OVERLAY SECURITY.”  Depending on the special ribbon selected, you can have up to two more overlay panels (YMCKOO) that allow you to add special security features to the cards without hologram lamination.  A third layer is represented with a basic barcode image printed by using the K panel on the back side of the card.

 

 

  

 

 

 

The ZC1/300 card printer series introduced new ribbons with different types of overlays and special panels that allow you to add different layers to the card. Some examples some shown below:

 

Zebra developed the new SDKs with the objective to make easy for developers to implement the layers concept. The image below indicates how the associations are made. PrintType selector in the SDK basically will define the layer. Depending on the ribbon, you can define how many layers for each card face can be printed. We'll review in this post the part of the code that is needed to implement this concept.

Ok, so let’s review the new requirements that were added to the app:

 

The steps to build the new app include:

  • Dynamically add three different images that the user will select from the device or a picture taken with the camera of the device.
  • Select the first image for the impression of the color layer
  • Select the second image for the impression of the overlay layer (adding some security effects to the card)
  • Select the third image for the impression of the mono/color layer on the back side of the card

 

The developers that attended the past workshop spent around one and a half hours to do the enhancements to the first app to implement dynamically the addition of the layers. Once implemented the logic, the developers played with the code and added up to 6 layers to the cards, so they created their own versions of code to print 3 layers for the front side, and 3 layers for the back side of the cards. Take in mind that the number of layers to be used depending upon the type of ribbon used.

 

Note: Not all printers support double-sided printing. ZC100 by default does not support double-sided printing. A kit to update will be needed to support double-sided printing. ZC300/350 supports double-sided printing by default.

 

There are different paths to do this. We selected the option below as we thought it is the simplest. The first step is developing a simple way to dynamically introduce the three images to the app, so the app can use them as layers. To implement this logic, we will be creating a simple string array of three images, and it will be transferred between activities.

 

In main Activity, we will be using a simple counter, and our new String array.

 

private String [] uriTransferPath;
private int counterimage=0;

 

We will still be using one imageSelectionSpinner, but we will be adding a short selector for the String array. It will be added in the onAtivityResult section for PICTURE_FROM_GALLERY as the graphic shows below.

 

if (requestCode == PICTURE_FROM_GALLERY) {
  Uri imgPath = data.getData();
  Log.i(TAG,"counter inicio"+ counterImage);
   // CALL THIS METHOD TO GET THE ACTUAL PATH
   File finalFile = new File(picPathFile.getPathFromUri(getApplicationContext(), imgPath));
  Log.i(TAG, String.valueOf(finalFile));

   if(finalFile.exists() && counterImage <= 3){
  Bitmap myBitmap = BitmapFactory.decodeFile(finalFile.getAbsolutePath());
   if(counterImage==0) {
  ImageView myImage = (ImageView) findViewById(R.id.imageFrontView);
  myImage.setImageBitmap(myBitmap);
   uriTransferPath[counterImage] = finalFile.toString();
  }
   if(counterImage==1){
  ImageView myImage = (ImageView) findViewById(R.id.imageFrontView1);
  myImage.setImageBitmap(myBitmap);
   uriTransferPath[counterImage] = finalFile.toString();
  }

   if(counterImage==2){
  ImageView myImage = (ImageView) findViewById(R.id.imageFrontView3);
  myImage.setImageBitmap(myBitmap);
   uriTransferPath[counterImage] = finalFile.toString();
  }

  Log.i(TAG, String.valueOf(file));
  Log.i(TAG,"counter inicio"+ counterImage);
   counterImage++;
  }

}

 

 

The same process should be done for the picture from TAKE_PICTURE.

On buttonCardUsb, do not forget to add a conditional statement to avoid a null pointer error.

 

buttonCardUsb.setOnClickListener(new View.OnClickListener() {
 public void onClick(View v) {
 
 Log.i(TAG, String.valueOf(uriTransferPath[0]));
 if(uriTransferPath[0]!=null) {
 Intent = new Intent(MainActivity.this, UsbDiscoveryAndPrintExample.class);
 intent.putExtra("imagePath", uriTransferPath);
 startActivity(intent);
 finish();
 }
 }
 });

 

The second step is focused in how we will be processing the three images, and how we will be sending them to the printer.

For that, we will be modifying our PrintCardHelper class as the image below shows.

 

private void generatePrintJobImage(final Context context, ZebraGraphics graphics, List<GraphicsInfo> graphicsData, String [] pathImage)
   throws IOException {
   for(int i=0; i<3; i++) {
   // Front Color Layer
   if(i==0) {
   byte[] imageData = FileUtils.readFileToByteArray(new File(pathImage[i]));
  graphics.initialize(context.getApplicationContext(), 0, 0, OrientationType.Landscape, PrintType.Color, Color.WHITE);
  graphics.drawImage(imageData, 0, 0, 0, 0, RotationType.RotateNoneFlipNone);
  graphicsData.add( buildGraphicsInfo(graphics.createImage(), CardSide.Front, PrintType.Color));
  graphics.clear();
  }
   // Front Full Overlay layer
   if(i==1){
   byte[] imageData = FileUtils.readFileToByteArray(new File(pathImage[i]));
  graphics.initialize(context.getApplicationContext(), 0, 0, OrientationType.Landscape, PrintType.Overlay, Color.WHITE);
  graphics.drawImage(imageData, 0, 0, 0, 0, RotationType.RotateNoneFlipNone);
  graphicsData.add( buildGraphicsInfo(graphics.createImage(), CardSide.Front, PrintType.Overlay));
  graphics.clear();
  }
   //Back side Color Type
   if(i==2) {
   byte[] imageData = FileUtils.readFileToByteArray(new File(pathImage[i]));
  graphics.initialize(context.getApplicationContext(), 0, 0, OrientationType.Landscape, PrintType.Color, Color.WHITE);
  graphics.drawImage(imageData, 0, 0, 0, 0, RotationType.RotateNoneFlipNone);
  graphicsData.add( buildGraphicsInfo(graphics.createImage(), CardSide.Back, PrintType.Color));
  graphics.clear();
  }
  }

}

 

Please consider updating the methods buildGraphicsInfo and generatePrintJobImage as the image below suggests, so you can transfer correctly the String Array and introduce each image as you wish for the layers available in your special ribbon.

 

With these simple changes, you'll be able to add nice visual effects or security layers to your cards. Don’t forget to make the modifications to the Android Layouts.

 

This blog was intended to familiarize you with the usage of layers with ZC300 card printers in Android. However, now you can replicate these concepts either in C# or Java. If you want to practice, you can do that with the initial code provided. Please refer to the first blog to understand the blog series sequence, and do the modifications by downloading the sample code on this GitHub link.

 

If you have any questions please, feel free to write your comments below.  Good luck coding!