jueves, 26 de junio de 2014

Array/Item problem on JAX-WS - Axis 1.x interation

A few days ago I encountered a little problem with a Webservice that I was asked to interact with. The client in question was on other country, and the permissions on the VPN were not granted already.
My normal workflow dealing with WS is first asking for the WSDL for mocking and building the artifacts. So I launched SoapUI and started working on the integration. All worked just well with the mocks, and for a little moment I thought that all will be joy and bliss.

The artifacts the JAX Import that I used gave me the following model:

Having worked with JAX-WS as a client and server, and only as client with the server being Axis2 for example, I thought that because of the signature of the Webservice Interface I was dealing with a JAX server on the other end.

But when the real connection was made (without Mocks) the attribute on CustomerSubscriptionInfo was comming null from the server. I tried a few more times with different input data but was the same. The person responsable for the other end said to me that there was data, that shouldn't be null. So after a few moments of head scratching I launched SoapUI and tried to see the difference between the mock and the real server.



The one on the left is the mock, and on the right is the real server response. Spot the difference? The subscriptions node was having the children different. The next thing I do was ask to the creator of the WS for the source code of those classes, something that may not always be available, but luckly for me was provided without a problem.

When I had the source code the first thing I realised was that the ArrayOfSubscriptionInfo class was missing, and that the actual model was:



The source code showed me that there was no ArrayOfSubscriptionInfo, there was only a simple array. Maybe this class was generated by JAX Importer, and when I asked which technology the server was implementing they sayed Axis1.4 (remember that I thought JAX-WS was the server).

So, after seeing the generated artifacts I saw and fixed the following:


// Before
public class CustomerSubscriptionInfo extends CustomerInfo {

    @XmlElement(required = true, nillable = true)
    protected ArrayOfSubscriptionInfo subscriptions;

    ...

// After
public class CustomerSubscriptionInfo extends CustomerInfo {

    @XmlElementWrapper(name="subscriptions")
    @XmlElement(required = true, nillable = true)
    protected SubscriptionInfo[] subscriptions;


I added the XmlElementWrapper annotation and replaced the ArrayOfSubscriptionInfo to an array of SubscriptionInfo. After this simple change it worked wonders!

So I guess you should really know your way around XML and the annotations...

domingo, 1 de junio de 2014

Java ESC/POS Image Printing

Hi! I've been wanting to do this post for a while. For many years I've been working from time to time with various printing issues, mainly in the context of Kiosk/Receipt printing.
The most common printer that I've used was an Epson Thermal Printer, such as the TM-T88III or more recently TM-T88V (which my article will treat).




One of the various requirements from my clients had been putting their logo on their receipts, and although you can upload the logo to the printer with a tool and tell the printer to print logo #1; this way can be very rigid and hard to maintain (changing the logo would require for me to go printer by printer uploading the new logo).


A better way is to raster the image pixel by pixel using ESC/POS, the native command language of the printer. Being a thermal printer, there is no concept of color, nor gray scale; either the pixel is burned or not burned, black or white. This is a very important concept to have in mind.
ESC/POS is Epson's proprietary set of commands for their printers, luckily there are some other manufacturers that comply with all or some commands so you can easily port it. Note however that some other manufacturers don't support it or have their own set of commands (like Zebra), but I think that the command operation won't differ much.



Understanding the command

Reading the documentation you'll find the following command:





Hardly the name of the command does it any honor to what is really done, but we'll settle with that. The first thing that pops up is that the command it has a constant and variable (or parametric) part , 1B 2A begin the constant part and m nL nH d1...dk being the variable part. A bit of a recommendation, don't send to the printer and/or don't use to the ASCII notation or format, stick with the Hex notation (or with the decimal notation). The ASCII notation can get confusing when you start mixing letters with bytes (in the end they are all bytes), also I prefer to have static final byte[] as a constant with the constant part of the command, like:



private final static char ESC_CHAR = 0x1B;
private final static char GS = 0x1D;
private final static byte[] LINE_FEED = new byte[]{0x0A};
private final static byte[] CUT_PAPER = new byte[]{GS, 0x56, 0x00};
private final static byte[] INIT_PRINTER = new byte[]{ESC_CHAR, 0x40};
private static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33};
private final static byte[] SET_LINE_SPACE_24 = new byte[]{ESC_CHAR, 0x33, 24};


The two first numbers (0x1B and 0x2A) are the command code, the following are parameters, neither of them must be left to chance. You must know exactly what to send in this parameters, otherwise the printer would not know what to do, will get blocked or print gibberish.



The m parameter specifies the dot density, and can have only 4 possible values m = 0, 1, 3, 33.




What this really means translated to english is the number of bytes we'll send at a time representing the image, I'll explain it latter with an example.


The nL and nH parameters represents the width of the image in pixels. nL is the low byte and nH is the high byte. Let's say that you want to print an image of 73 pixels, then the parameters would be nL = 0x49 and nH = 0. Or if the image is 300 pixels wide, nL = 0x2C and nH = 0x01.



I'll repeat it one more time, this parameters need to be set properly and can vary from image to image. Do this or you printer will lock or print gibberish.



Other important concept to grasp is that the printer will print the image in stripes of the selected dot density. Let's say that you image is of 73x48 pixels and you choose m = 33 (24-dot density), the your image would be printed in two stripes of 73x24. An explanation of why the previous parameters of the actual image data are important is that once you feed all the pixel information the printer will resume to normal text printing mode, so if you put for example m = 0 (8-dot density), nL = 0x05 and nH = 0x0, then you must provide an array of 5 bytes (8 bits x 5 dots wide, bit density chosen x width of the image).


Understanding how the image is printed
If you've done any amount of rendering programming you know that you raster the image on the screen in scan lines left to right, top to bottom. But with this printers, the rasterization is done top to bottom, left to right. Is important to have this in mind when sending the image data. This have to do with how the thermal printer head prints the data.
If we've a image of 8 pixels high and w pixels wide the data will be sent:


In this example, we get the image in an array of pixels in the following order [px0, px1, ..., pxw, ..., px8w], but the "same" data must be sent the printer in another order: [d0, d1, d2, ..., d k].

Like I said before, there is no concept of color in thermal printing, either the pixel is burn or is not. So each pixel will be a bit not the color itself, and we'll be sending multiple pixels per byte.

Understanding how the image is printed
Let's start with some warm up exercises:

Send the printer [0x1B, 0x2A, 0x0, 0x5, 0x0, 128, 64, 32, 16, 8] (I changed from hex to decimal for clarity).
You should see a descending line of 5 dots. Let's explain what have we done here, we've selected the 8-bit density mode, and the width of the image is 5px (all in hex). The following decimals are the px data sent:


You can add 3 more dots to the line, I left to you as an exercise to complete the line, but remember you'll need to change the nL parameter.

Now let's get to real stuff, let's get the pixels of an image:


BufferedImage bi = (BufferedImage) image.getImage();
int[][] pixels = getPixelsSlow(bi);

...
// The performance of this method 
// is rather poor, place for improvement
private int[][] getPixelsSlow(BufferedImage image) {
    int width = image.getWidth();
    int height = image.getHeight();
    int[][] result = new int[height][width];
    for (int row = 0; row < height; row++) {
        for (int col = 0; col < width; col++) {
            result[row][col] = image.getRGB(col, row);
        }
    }

    return result;
}


Actually printing the image
Once you have the image in an array of pixels, let's print them:

private void printImage(int[][] pixels) {
 // Set the line spacing at 24 (we'll print 24 dots high)
 printPort.writeBytes(SET_LINE_SPACE_24);
 for (int y = 0; y < pixels.length; y += 24) {
  // Like I said before, when done sending data, 
  // the printer will resume to normal text printing
  printPort.writeBytes(SELECT_BIT_IMAGE_MODE);
  // Set nL and nH based on the width of the image
  printPort.writeBytes(new byte[]{(byte)(0x00ff & pixels[y].length)
                             , (byte)((0xff00 & pixels[y].length) >> 8)});
  for (int x = 0; x < pixels[y].length; x++) {
   // for each stripe, recollect 3 bytes (3 bytes = 24 bits)
   printPort.writeBytes(recollectSlice(y, x, pixels));
  }

  // Do a line feed, if not the printing will resume on the same line
  printPort.writeBytes(PrinterCommands.FEED_LINE);
 }
 printPort.writeBytes(SET_LINE_SPACE_30);
}

private byte[] recollectSlice(int y, int x, int[][] img) {
    byte[] slices = new byte[] {0, 0, 0};
    for (int yy = y, i = 0; yy < y + 24 && i < 3; yy += 8, i++) {
        byte slice = 0;
 for (int b = 0; b < 8; b++) {
            int yyy = yy + b;
     if (yyy >= img.length) {
         continue;
     }
     int col = img[yyy][x]; 
     boolean v = shouldPrintColor(col);
     slice |= (byte) ((v ? 1 : 0) << (7 - b));
 }
        slices[i] = slice;
    }
 
    return slices;
}

private boolean shouldPrintColor(int col) {
    final int threshold = 127;
    int a, r, g, b, luminance;
    a = (col >> 24) & 0xff;
    if (a != 0xff) {// Ignore transparencies
        return false;
    }
    r = (col >> 16) & 0xff;
    g = (col >> 8) & 0xff;
    b = col & 0xff;

    luminance = (int) (0.299 * r + 0.587 * g + 0.114 * b);

    return luminance < threshold;
}

If you've done everything right you should see the image printed, if not check the steps again:



Interfacing
In the code that I've used the interfacing can take place with a serial port or with an USB port. For this purpose I been using this two great libraries:


If you can, try to support this guys you can't imagine the great deal of pain that you're saving yourself.

Side notes
I know there still room for improvement, some parts of the code are not production ready. For example you could cache the bitwise representation of the image.
If you want to ask me some question feel free to send me an email. 

Source code
All this knowledge was derived from my previous job. I was tasked to develop a printing service/daemon that would print tickets remotely (on a Kiosk, where a server would issue priting requests).
I removed all the project related code to avoid legal issues, and I'm attaching the server part of the code (not the client, although you don't need it for this).
You can pack this project in a JAR file and use the Main class to test it right away, all the needed libraries are bundled.


Small source explanation:
Let me explain a little bit about the classes that are inside the project.

TicketPrinterJob: This class represents an abstraction of a print job. Contains a list "lines", what this means is that the job is printed in a plain text fashion, line after line (whether is text or image).
TicketPrinterJobLine: Abstraction about the line to be printed. This class is inherited by TicketPrinterJobText and TicketPrinterJobImage, that would print a line of text or an image respectively.
EscPosStrategy: This class gets the job done, it send the proper ESC/POS commands and data bytes to the printer. Has a print public method that accepts a print job.

For the moment I don't have access to a ESC/POS printer so this code isn't properly tested. Please contact me if you have any problems.

References

Edit #1: I revisit and reworked some parts of the article to enhance comprehension and clarity.

Edit #2 (2015/03/31): Thanks to Daniel Bernard for pointing out that the source code didn't worked. Attaching proper files.