miércoles, 18 de mayo de 2016

Responsive tinyMCE


On a project that I'm working we're using an old version of tinyMCE (https://www.tinymce.com/), specifically we are using version 3.4.5 (released in 2011).

Since last year we've been focusing on making the site responsive, and we've a bunch of legacy stuff that we could improve and use newer version of the libraries that comes bundled with the system.
Making this rich-text editor responsive is a little tricky since its header or toolbar is defined as a table, and its buttons as table cells. After tweaking the details I came with the following solution:

.mceLayout,
.mceToolbar {
 display: block;
 height: initial !important;
}

.mceLayout > tbody,
.mceLayout > tbody > tr,
.mceToolbar > tbody,
.mceToolbar > tbody > tr {
 display: block;
}

.mceLayout tr.mceFirst td.mceToolbar {
        background: #F6F6F6;
 height: initial !important;
 overflow: hidden;
 width: 100%
}

tr.mceIframeRow td {
 display: block;
 float: left;
 height: 28px;
}

I'm sorry about the !importants, please feel free to remove them if you don't need them on your codebase. Hope it helps!

PS: Note that the last version of tinyMCE are actually responsive, this hack is only for old version (assuming you can't upgrade)

jueves, 27 de noviembre de 2014

Books I have read this year (2014)

Well after thinking a little about it I decided to do a post about the books I read this year (2014), I didn't committed to any particular number of books but in the previous year I resumed my reading hobby, and this year started buying books like crazy. So I wanted to write a little about each book:


Atlas Shrugged (Ayn Rand)

To be fair, I started reading this book in 2013 but finished it this year (it's a big book!) and also wanted to write about it. This is a awesome book, full of details and ideas; Ayn Rand magnum opus is a must read. In it she develops her Objectivism philosophy, each character embodying an archetype around it.
It's a lengthy book, even some parts are very boring (for example, the John Galt's monologue is too much, could be shorten very much), but for the most chapters the writing is great and it gets you thinking about some of your values, principles and thoughts about life it self and life in society.
I liked that the book is written in a timeless fashion, not attached over to any age or time (but certainly some parts seems like it), and that the characters represented different sides of human beings, and how the deal with real life. A common dislike is that characters appear simple and not fully fleshed, they stick to their archetype and never loose it; at certain points of the story this was pretty evident but I didn't find it bothering, boring or disliking.
Lastly, I put here a quote by John Rogers that I find very funny: 
There are two novels that can change a bookish fourteen-year old's life: The Lord of the Rings and Atlas Shrugged. One is a childish fantasy that often engenders a lifelong obsession with its unbelievable heroes, leading to an emotionally stunted, socially crippled adulthood, unable to deal with the real world. The other, of course, involves orcs.

A Feast of Crows (George RR Martin)

I feel sorry about reading this book, after the first three excellent books, this one seems like a step-back. Many of the loved characters of the previous books are gone, and those that are in it looks like are there only for filling pages. I love story about Aria, it's a great story but in Feast, the whole story at Braavos and the guild of faceless men it's very tedious and boring.
And the other characters are unfamiliar and unappealing, the two uncles of Theon Greyjoy feel like made of cardboard, with no depth or sympathy. The two behave almost the same, by some archetype without considering other options or choices.
The character development is non-existent making the novel unappealing, also I don't remember being exited at any moment (I think that not a single important character dies at this novel, nor you feel bravery, shame or dislike to any character's action).
I only hope that A Dance With Dragons improves upon this one.


Anthem (Ayn Rand)

So after reading Atlas Shrugged I wanted to know and read more about Objectivism and Ayn Rand, so I buy several Rand's books. This one seems like Atlas' small brother, you feel the ideas of Objectivism forming up, I really enjoyed the way it's written and how it removed the "I" from the characters vocabulary. Also the book is a very gentle introduction (if you haven't read anything of Rand's work) that you can read in a day.







The Virtue of Selfishness / Capitalism: The unknown ideal (Ayn Rand) 

So after reading Atlas Shrugged I wanted to know and read more about Objectivism and Ayn Rand, so I buy several Rand's books. This two books fell pretty much the same, the core ideas of Objectivism and Selfishness are exposed over and over again. If I had to choose, I kept Capitalism as a must read.
Both books divide the chapters in different papers or discourses made Rand it self or other Objectivism advocates, so you might get the same idea over and over again, getting a little repetitive.



Clojure Programming (Chas Emerick) 

Great book about Clojure, I strongly recommend it if you want to get started on clojure. If filled with detail and examples, it would be great if it had some exercises for you to complete. I wish to get the chance to use clojure at my workplace environment.










Pensamiento Nacional para Principiantes (Tello, National philosophy for beginners)

This book deals mainly with Argentinian thinkers and the ideas they spawned over the history of the country, trying to create ideas and philosophies different that the europeans or to adapt those one to the national idiosyncratic. It's a great book if you want an introduction to the popular national thinking of the country, also relates every character with the context of the moment, and how the context molded this persons and how they influenced this context and the future. Also I liked that the book left out relatively new characters, like Menem or Kirchner, and focused over the thinkers like Jauretche and Ortiz.




Economia para principiantes (Garvie, Economics for beginners)

This book deals with the evolution of economy as a science, from Ancient Greek to modern days. It's a great introduction to the discipline in a way that explains how every great economy school was made. Regretfully it leaves out the mathematical side and it doesn't explain you anything about real economics, it only tells you the problems each new school tried to solve (and what new problems brought to the table).
Including economists like Adam Smith, John Keynes and others, each explaining how they see the world (or more like the economic world, but nowadays whats the difference?). It really get me thinking about how each thinker has influenced what it should be done politically speaking in order for a country to thrive, and how this is seen in modern country, how they apply it.


Fahrenheith 451 (Ray Bradbury)

As an overall it's a good book, I enjoyed it, but I think that is somehow hyped. Please don't get me wrong, is a great book with a great parody, analogy and critic of modern society that I feel everyday (people not reading enough or at all, governments thinking that they know what's best for us, dealing with oppression). But after reading it, I fell something missing, some last revelation or realization of some kind.







1984 (George Orwell)

Absolutely an awesome book, the first part is a bit slow and tedious, but once it gains momentum it gets really good. I can't help myself of tracing analogies with real life, with life in modern society, with politics and with real power (and powers). From the optimistic side you feel like you change change the world if you set your mind to it, that love is a life changing emotion that make you touch the sky. From the pessimistic side you fill tiny, alone and broken, that nothing can we make of this unstoppable tide that we call society, human kind; that for some people power and money is all there is, no matter how many "bugs" must he crush.
The book's ending is entirely unexpected, more than one should be left with a WTF. Nonetheless, in context is a awesome book, a must read.


Einstein: El espacio es una cuestion de tiempo (Einstein: Space is a matter of time)

A very gentle introduction to Einstein theories and discoveries, it also serves as biographical piece. I think is a very good book, a national newspaper is releasing this books weekly, and although I would dig some more math in it the overall picture the problems, theories and solutions are very well explained.






Matematicas, ¿Estas ahi? (Paenza, Mathematics, are you there?)

Over the last few months I wanted to increase my use of mathematics in life in general (and also to get a better grasp over the whole topic) because I really enjoyed my Calculus and Linear Algebra classes over at college. I don't think is a great book, it's good, but seems very convoluted and appears that jumps topic to topic with no correlation or clear intention. Although I didn't like the way it's written, Paenza is great at explaining math, they were very clear. I only would like that there were more exercises and more examples related with real life (say, how can you win the lottery knowing math! hehe).




Destination: Void (Frank Herbert)

Remember when I say'd that started buying books like crazy, well it all started after wanting to read more about Frank Herbert (my favorite author for its work Dune). Regretfully I wasn't able to find a whole lot of books in my country, his work isn't very well divulged and if it isn't mainstream nobody cares to print old books (although it make sense), but I buy some used books, this in particular it's almost my age (it was printed on 1987).
This is an awesome book, not as good as Dune but very good. It focus on consciousness, what's consciousness, what we understand it is, what are the fundamental requirements for it to develop on a sentient being and what the new stage of consciousness. Like Dune, it takes in someway a Zen approach (a religion Herbert was devoted and later on his life converted from Catholicism) to the consciousness issue. I really liked that this book doesn't focus on the technical side of science fiction (much like Herbert has always done), to tell you the truth I don't enjoy when an author get so fixed on technology and gadgets, for me it all revolves around characters, their interactions, decisions and actions.
Each character embodies a different approach in reaching nirvana, the path of faith, the path of science, the path of knowledge; without forgetting about the ship which is like the fifth character of the book I was rushing through the pages to know when Frankenstein creation will be awaken, not to say what an ending!

Special mention

Well, after reading a lot of Ayn Rand I got really hooked up with philosophy and capitalism, but I wanted to read also someone that criticizes capitalism (if not, I would be biased). And who's best to bring down capitalism if not Karl Marx,  so I bought Marx's Capital and started reading it but really couldn't finish it. The whole time it make me feel that I was a stupid, like if someone tried to explain this to ants. Nonetheless I didn't get frustrated, it got me thinking a lot, so that's a good sign but I jumped over other books, someday I'll finish it...
I also read a book about sleeping and the study of sleep, but it was pretty boring and short (I finished in two days, though I did a lot of skimming) so I didn't wanted to add it to list.

viernes, 4 de julio de 2014

Processing Augmented Reality Tutorial - Part 1

Introduction

For a presentation with a Studio that I'm currently working we decided to do feature an augmented reality show. Something simple for people that had little or none experience with AR.
So after doing a little research about what technologies supported AR I decided to use Processing, which I'd never used, but after learning that was a Java environment I supposed that would fit in my confort zone.

Searching I found the following tutorial: Augmented reality tutorial with #Processing

To tell you the truth I struggled a lot with the libraries and the code from that tutorial, I don't understand why there is no indentation (seems like the work of a junior programmer, not trying to offende the author), the interaction with the libraries is buggy, and some of the code is incomplete. But none the less serves as generally good introduction, so let's start from there...

First, I won't be using Processing in the environment provided, but using directly Java with a Netbeans as IDE (but any will do). I'll try to follow the same order of the other tutorial.

The libraries you'll need are:
Processing 2.1 (Win64) or Processing 2.1 (Win32) (if you're working with another SO, go here).
NyARToolkit 1.1.6 (The library responsible for the pattern recognition among other things).
English NyAR4psg 1.1.6 (I had to translate the source code to understand it, also I was getting a renderer error with the other library that I coundn't figure out. I'm sorry if its no properly translated, it was in Japanese).
Pattern files (Pattern files need for the tutotial, QR markers).

You'll need the image from the tutorial to get the first example working, you can download it from here.

Environment preparation

Once you unzip the Processing library in the folder of your choosing (mine is in the Downloads folder, we'll name it processing_folder), create a folder in named processing in the user's documents folder (I think this folder is created by executing processing.exe, but really can't remember, we'll name it processing_workspace), and inside it create another folder named libraries. Inside this later folder decompress NyARToolkit. Lastly in the processing_workspace create a nmoncho-nyar4psg-1.1.6 and unzip the English NyAR4psg library.
The final layout should be like:




After doing this launch your IDE, Netbeans in my case, create a new Java Application (ARTutorial for example) and add the following libraries to the project:
  • [processing_folder]/core/library/core.jar
  • [processing_folder]/core/library/gluegen-rt.jar
  • [processing_folder]/core/library/gluegen-rt-natives-[your SO-architecture].jar
  • [processing_folder]/core/library/jogl-all.jar
  • [processing_folder]/core/library/jogl-all-natives[your SO-architecture].jar
  • [processing_workspace]/libraries/nyar4psg-1.1.6/library/NyAR4psg.jar
  • [processing_workspace]/libraries/nyar4psg-1.1.6/library/NyARToolkit.jar
  • [processing_workspace]/libraries/nmoncho-nyar4psg-1.1.6/nmoncho-nyar4psg.jar

In your project properties, in the Libraries panel you should see:



In the root folder of the project you must put the image file (input.jpg), and create a folder named "patterns" and unzip the pattern files provided in the download section. Also, you must copy the " " file from [processing_workspace]/libraries/nyar4psg-1.1.6 folder.


Code

For this example I created a Example01 class:

package artest;

import java.io.File;
import java.io.FilenameFilter;
import processing.core.PApplet;
import processing.core.PImage;
import processing.core.PVector;

public class Example01 extends PApplet {
    
    /** Relative path to "camera_para.dat" file located in the NyARToolkit library folder. */
    private static final String CAMERA_PARA_FILE_PATH = "camera_para.dat";
    
    /** Absolute path to the folder containg the patterns. */
    private static final String PATTERNS_FOLDER = "patterns/";
    /** Extension of pattern files. */
    private static final String PATTERN_FILE_EXTENSION = ".patt";

    /** Resolution of the sketch. */
    private static final int SKETCH_WIDTH = 640, SKETCH_HEIGHT = 480;
    
    private com.nmoncho.nyar4psg.MultiMarker nya;
    private float displayScale;
    private int patternsLoaded;
    private int[] boxColors;
    private float[] boxScales;
    private PImage inputImage, scaledInputImage;
    
    @Override
    public void setup() {
        size(SKETCH_WIDTH, SKETCH_HEIGHT, OPENGL);
        inputImage = loadImage("input.jpg");
        scaledInputImage = inputImage.get();
        scaledInputImage.resize(SKETCH_WIDTH, SKETCH_HEIGHT);
        displayScale = (float) width / SKETCH_WIDTH;
        
        nya = new com.nmoncho.nyar4psg.MultiMarker(this, SKETCH_WIDTH, SKETCH_HEIGHT
                , CAMERA_PARA_FILE_PATH, com.nmoncho.nyar4psg.NyAR4PsgConfig.CONFIG_DEFAULT);
        patternsLoaded = loadPatterns(nya, PATTERNS_FOLDER);
        boxColors = new int[patternsLoaded];
        boxScales = new float[patternsLoaded];
        
        for (int i = 0; i < patternsLoaded; i++) {
            boxColors[i] = color(random(255f), random(255f), random(255f), 160f);
            boxScales[i] = random(0.5f, 1.9f);
        }
    }
    
    @Override
    public void draw() {
        // in the other tutorial is used "background(0)" instead
        // but don't works properly, you'll see a black screen
        background(scaledInputImage); 

        nya.detect(scaledInputImage);
        drawMarkers();
        drawBoxes();
    }
    
    /**
     * Draws red dots in each marker's vertex, and tags its coordinates.
     */
    private void drawMarkers() {
        textAlign(TOP, LEFT);
        textSize(10);
        noStroke();
        scale(displayScale);
        ortho();
        for (int i = 0; i < patternsLoaded; i++) {
            if (nya.isExistMarker(i)) {
                PVector[] pos2d = nya.getMarkerVertex2D(i);
                for (int j = 0; j < pos2d.length; j++) {
                    String coordinate = "(" + (int) pos2d[j].x + ", " + (int) pos2d[j].y + ")";
                    fill(255);
                    rect(pos2d[j].x, pos2d[j].y - 10, textWidth(coordinate) + 3, textAscent() + textDescent() + 3);
                    fill(0);
                    text(coordinate, pos2d[j].x + 2, pos2d[j].y + 2);
                    fill(255, 0, 0);
                    ellipse(pos2d[j].x, pos2d[j].y, 5, 5);
                }
            }
        }
    }
    
    /**
     * Draws 3D boxes over the patterns detected
     */
    private void drawBoxes() {
        final float boxInitialSize = 40;
        textAlign(CENTER, CENTER);
        textSize(20);
        
        for (int i = 0; i < patternsLoaded; i++) {
            if (nya.isExistMarker(i)) {
                nya.beginTransform(i);
                scale(1, -1);
                scale(boxScales[i]);
                fill(boxColors[i]);
                lights();
                stroke(0);
                box(boxInitialSize);
                noLights();
                translate(0, 0, boxInitialSize/2 + .1f);
                noStroke();
                fill(255, 50);
                rect(-boxInitialSize/2, -boxInitialSize/2, boxInitialSize, boxInitialSize);
                translate(0, 0, 0.1f);
                fill(0);
                text("" + i, -boxInitialSize/2, -boxInitialSize/2, boxInitialSize, boxInitialSize);
                nya.endTransform();
            }
        }
    }
    
    /**
     * Loads the pattern files located in the specified folder into the multimarker.
     * @param multimarker Multimarker to load patterns.
     * @param pathToPatternFolder folder containing pattern files.
     * @return amount of pattern loaded.
     */
    private int loadPatterns(com.nmoncho.nyar4psg.MultiMarker multimarker, String pathToPatternFolder) {
        File folder = new File(pathToPatternFolder);
        if (folder.exists() && folder.isDirectory()) {
            File[] patterns = folder.listFiles(new FilenameFilter() {

                @Override
                public boolean accept(File dir, String name) {
                    return name.toLowerCase().endsWith(PATTERN_FILE_EXTENSION);
                }
            });
            if (patterns.length == 0) {
                throw new IllegalArgumentException("The " + pathToPatternFolder 
                        + "doesn't contain any pattern file (.patt)");
            }
            
            for (int i = 0; i < patterns.length; i++) {
                multimarker.addARMarker(patterns[i].getAbsolutePath(), 80);
            }
            
            return patterns.length;
        }
        
        return 0;
    }
    

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        PApplet.main(new String[] { "--present", Example01.class.getCanonicalName() });
    }
}


I changed several things from the other tutorial
  1. Line 68: Added an othro() call, this is necessary because when you draw the boxes, it changes the projection to perspective, so you have to change it back. If you don't do this you won't see the red dots and the coordinate labels.
  2. Line 95 and 110: Removed the calls to nya.setARPerspective(), setMatrix(nya.getMatrix(i)) and perspective() and replaced it with beginTransform() and endTransform().
You can download the source code of the project.

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.