I want to print a Bitmap to a mobile Bluetooth Printer (Bixolon SPP-R200) - the SDK doesn't offer direkt methods to print an in-memory image. So I thought about converting a Bitmap like this:

Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

To a Monochrome Bitmap. I am drawing black text on above given Bitmap using a Canvas, which works well. However, when I convert the above Bitmap to a ByteArray, the printer seems to be unable to handle those bytes. I suspect I need an Array with one Bit per Pixel (a Pixel would be either white = 1 or black = 0).

As there seems to be no convenient, out of the box way to do that, one idea I had was to use:

bitmap.getPixels(pixels, offset, stride, x, y, width, height)

to Obtain the pixels. I assume, I'd have to use it as follows:

int width = bitmap.getWidth();
int height = bitmap.getHeight();


However - I am not sure about a few things:

  • In getPixels - does it make sense to simply pass the width as the "Stride" argument?
  • I guess I'd have to evaluate the color information of each pixel and either switch it to black or white (And I'd write this value in a new target byte array which I would ultimately pass to the printer)?
  • How to best evaluate each pixel color information in order to decide that it should be black or white? (The rendered Bitmap is black pain on a white background)

Does this approach make sense at all? Is there an easier way? It's not enough to just make the bitmap black & white, the main issue is to reduce the color information for each pixel into one bit.


As suggested by Reuben I'll first convert the Bitmap to a monochrome Bitmap. and then I'll iterate over each pixel:

    int width = bitmap.getWidth();
    int height = bitmap.getHeight();


    // Iterate over height
        int offset = y * height;
        // Iterate over width
            int pixel = bitmap.getPixel(x, y);

Now Reuben suggested to "read the lowest byte of each 32-bit pixel" - that would relate to my question about how to evaluate the pixel color. My last question in this regard: Do I get the lowest byte by simply doing this:

// Using the pixel from bitmap.getPixel(x,y)
int lowestByte = pixel & 0xff;
  • I have this QA starred because I was working on a similar concept with regards to programmatically manipulating arrays to become monochrome bitmaps. I have a question & its eventual answer here: stackoverflow.com/questions/17918978/… If this helps people, please email me and I'll come up with a suitable answer to this question. – Chris K Dec 28 '13 at 9:16
  • 1
    Why are you using GetPixels to load all the pixels into a single array... Then nested looping through the bitmap AGAIN calling individual GetPixel calls (the least efficient way possible)? Just loop through your original array, then use SetPixels to push the entire array back into the bitmap. – Clint StLaurent Mar 14 '16 at 16:17
  • @ClintStLaurent good point - the code is really old xD - I don't even think we're using it in this form anymore, but as you pointed out correctly, it is very inefficient the way it's written there. Feel free to edit it according to your suggestion. – AgentKnopf Mar 15 '16 at 19:20

You can convert the image to monochrome 32bpp using a ColorMatrix.

Bitmap bmpMonochrome = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmpMonochrome);
ColorMatrix ma = new ColorMatrix();
Paint paint = new Paint();
paint.setColorFilter(new ColorMatrixColorFilter(ma));
canvas.drawBitmap(bmpSrc, 0, 0, paint);

That simplifies the color->monochrome conversion. Now you can just do a getPixels() and read the lowest byte of each 32-bit pixel. If it's <128 it's a 0, otherwise it's a 1.

|improve this answer|||||
  • Thank you very much for your answer! Just to clarify the pixel evaluation I updated my question (below UPDATE) essentially: do I get the lowest byte of a 32-bit int by doing this: int lowestByte = pixel & 0xff; ? – AgentKnopf Feb 21 '12 at 13:12
  • 1
    Yes. Actually bit 7 of the lowest byte is exactly the bit you want for your 1bpp pixel. The expression '(pixel & 0x80) >> 7' will give you a '0' or '1' for that. – Reuben Scratton Feb 21 '12 at 13:26
  • On an additional note: Can it be, that the byte array I produce is not readable by android? Using BitmapFactory.decodeByteArray(imageInBytes, 0, imageInBytes.length) returns no usable Bitmap (to display in android), and the printer doesn't like it neither... – AgentKnopf Feb 21 '12 at 15:42
  • 2
    Well firstly, Android doesn't support 1bpp bitmaps, and secondly BitmapFactory.decode* exists to decode PNG & JPEG formats. You will need to refer to the printer's documentation and work out exactly what it does support. – Reuben Scratton Feb 21 '12 at 16:10
  • Thanks for the clarification - jepp the printers SDk is a bit messy :( it can print images from the web & file system but it can't print in-memory images, that's why I thought about sending the bits directly... I'll keep trying :) – AgentKnopf Feb 21 '12 at 16:16

Well I think its quite late now to reply to this thread but I was also working on this stuff sometimes back and decided to build my own library that will convert any jpg or png image to 1bpp .bmp. Most printers that require 1bpp images will support this image (tested on one of those :)). Here you can find library as well as a test project that uses it to make a monochrome single channel image. Feel free to change it..:)


Enjoy..!! :)

|improve this answer|||||
  • Thanks for the effort! I am sure it'll be helpful to others and I'll go take a look at the project you posted as well :) . – AgentKnopf Mar 20 '13 at 10:02

You should convert each pixel into HSV space and use the value to determine if the Pixel on the target image should be black or white:

  Bitmap bwBitmap = Bitmap.createBitmap( bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.RGB_565 );
  float[] hsv = new float[ 3 ];
  for( int col = 0; col < bitmap.getWidth(); col++ ) {
    for( int row = 0; row < bitmap.getHeight(); row++ ) {
      Color.colorToHSV( bitmap.getPixel( col, row ), hsv );
      if( hsv[ 2 ] > 0.5f ) {
        bwBitmap.setPixel( col, row, 0xffffffff );
      } else {
        bwBitmap.setPixel( col, row, 0xff000000 );
  return bwBitmap;
|improve this answer|||||

Converting to monochrome with exact the same size as the original bitmap is not enough to print.

Printers can only print each "pixel" (dot) as monochrome because each spot of ink has only 1 color, so they must use much more dots than enough and adjust their size, density... to emulate the grayscale-like feel. This technique is called halftoning. You can see that printers often have resolution at least 600dpi, normally 1200-4800dpi, while display screen often tops at 200-300ppi.


So your monochrome bitmap should be at least 3 times the original resolution in each side.

|improve this answer|||||
  • You mean dithering by any chance? I had dithering already integrated into my code :) – AgentKnopf Aug 2 '13 at 8:26
  • No. Dithering is a comletely different business. In 8-bit or more grayscale bitmap there's 255 (or more, depending on how many bits you use) levels of grey, so the original resolution is fine. But if you use monochrome bitmap then almost all details will be lost significantly because you're reducing from more than 16.7 million colors to only 2. Halftoning increases resolution and uses extra pixels to give the effect of grayscale as a way to pass this limitation. You can reference the link I gave above. – phuclv Aug 2 '13 at 9:12
  • Ah, thanks for clearing that up :) ! In my particular use-case I already draw on a canvas in Black & white. However it can also happen that we print photographs, so for these cases half-toning might really come in handy - thanks again :) ! – AgentKnopf Aug 2 '13 at 10:02

Your Answer

