7

I am reading a raw image from the network. This image has been read by an image sensor, not from a file.

These are the things I know about the image:
~ Height & Width
~ Total size (in bytes)
~ 8-bit grayscale
~ 1 byte/pixel

I'm trying to convert this image to a bitmap to display in an imageview.

Here's what I tried:

BitmapFactory.Options opt = new BitmapFactory.Options();
opt.outHeight = shortHeight; //360
opt.outWidth = shortWidth;//248
imageBitmap = BitmapFactory.decodeByteArray(imageArray, 0, imageSize, opt);

decodeByteArray returns null, since it cannot decode my image.

I also tried reading it directly from the input stream, without converting it to a Byte Array first:

imageBitmap = BitmapFactory.decodeStream(imageInputStream, null, opt);

This returns null as well.

I've searched on this & other forums, but cannot find a way to achieve this.

Any ideas?

EDIT: I should add that the first thing I did was to check if the stream actually contains the raw image. I did this using other applications `(iPhone/Windows MFC) & they are able to read it and display the image correctly. I just need to figure out a way to do this in Java/Android.

OceanBlue
  • 9,142
  • 21
  • 62
  • 84

4 Answers4

14

Android does not support grayscale bitmaps. So first thing, you have to extend every byte to a 32-bit ARGB int. Alpha is 0xff, and R, G and B bytes are copies of the source image's byte pixel value. Then create the bitmap on top of that array.

Also (see comments), it seems that the device thinks that 0 is white, 1 is black - we have to invert the source bits.

So, let's assume that the source image is in the byte array called Src. Here's the code:

byte [] src; //Comes from somewhere...
byte [] bits = new byte[src.length*4]; //That's where the RGBA array goes.
int i;
for(i=0;i<src.length;i++)
{
    bits[i*4] =
        bits[i*4+1] =
        bits[i*4+2] = ~src[i]; //Invert the source bits
    bits[i*4+3] = 0xff; // the alpha.
}

//Now put these nice RGBA pixels into a Bitmap object

Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bm.copyPixelsFromBuffer(ByteBuffer.wrap(bits));
Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281
  • @Seva Alekseyev: Thanks for the answer. I tried out your suggestion. Am getting a Runtimeexception. As per the logcat "Buffer not large enough for pixels". I'm creating the Bitmap using width & height of the image. – OceanBlue Apr 12 '11 at 15:25
  • @OceanBlue: The message suggests that the Bits buffer is less than 4*Width*Height bytes long. Check if it is. ARGB_888 is a 4 bytes per pixel format. – Seva Alekseyev Apr 12 '11 at 15:29
  • @Seva Alekseyev: I know for sure that Bits buffer is Width*Height bytes long. The image is 1 byte per pixel format. So even if I create a byte array 4 times the size, the image would be stored in the first 1/4th part of it. Would you happen to know any "1 byte per pixel" format in Android? – OceanBlue Apr 12 '11 at 21:28
  • @Seva Alekseyev: Thanks for your continued support. I do see an image (Yoohoo!!!) . For some strange reason, it is drawn **white lines on cyan background** instead of **black lines on white background**. If you happen to know the reason, I'd much appreciate it. – OceanBlue Apr 13 '11 at 15:11
  • You probably took the first version of my code snippet, with a typo in it. There was 1 instead of 3 in the last loop line, so the red bits were not initialized. – Seva Alekseyev Apr 13 '11 at 15:37
  • Oh, and another point: it seems like the image source device thinks 0 is white, 1 is black. Android thinks otherwise. So if you see your image in inverted colors - white instead of black and vice versa - just invert the source byte. See edit2. – Seva Alekseyev Apr 13 '11 at 15:43
  • Anyways, thanks for your guidance, +1 & marking accept. I'll dig in more to figure out why white is turning cyan & black/gray turning white – OceanBlue Apr 13 '11 at 15:49
  • Oh I just saw your EDIT2. Tried it. It looks **much** better, I think the inversion was there. It still is dark cyan lines on very light cyan background. Somehow the red bits are not being initialized as you mentioned... – OceanBlue Apr 13 '11 at 16:00
  • Now I'm not sure if I got the structure of RGBA right. See edit3. – Seva Alekseyev Apr 13 '11 at 16:12
  • That was it (RGBA)! It is showing up perfectly now. Much appreciate your sticking with me to get it resolved! – OceanBlue Apr 13 '11 at 16:36
1
for(i=0;i<src.length;i++)
{
    bits[i*4] = bits[i*4+1] = bits[i*4+2] = ~src[i]; //Invert the source bits
    bits[i*4+3] = 0xff; // the alpha.
}

The conversion loop can take a lot of time to convert the 8 bit image to RGBA, a 640x800 image can take more than 500ms... A quicker solution is to use ALPHA8 format for the bitmap and use a color filter:

//setup color filter to inverse alpha, in my case it was needed
float[] mx = new float[]{
    1.0f, 0, 0, 0, 0, //red
    0, 1.0f, 0, 0, 0, //green
    0, 0, 1.0f, 0, 0, //blue
    0, 0, 0, -1.0f, 255 //alpha
};

ColorMatrixColorFilter cf = new ColorMatrixColorFilter(mx);
imageView.setColorFilter(cf);

// after set only the alpha channel of the image, it should be a lot faster without the conversion step

Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
bm.copyPixelsFromBuffer(ByteBuffer.wrap(src));  //src is not modified, it's just an 8bit grayscale array
imageview.setImageBitmap(bm);
1

Once I did something like this to decode the byte stream obtained from camera preview callback:

    Bitmap.createBitmap(imageBytes, previewWidth, previewHeight, 
                        Bitmap.Config.ARGB_8888);

Give it a try.

Lukas
  • 455
  • 4
  • 11
  • 3
    Thanks for the answer. What does the first parameter "imageBytes" contain? Of all the overloaded versions of Bitmap.createBitmap(...) that I see in online Javadocs, none takes a byte array as a parameter. – OceanBlue Apr 12 '11 at 14:17
0

Use Drawable create from stream. Here's how to do it with an HttpResponse, but you can get the inputstream anyway you want.

  InputStream stream = response.getEntity().getContent();

  Drawable drawable = Drawable.createFromStream(stream, "Get Full Image Task");
Brian Griffey
  • 4,751
  • 1
  • 25
  • 26
  • Thanks for your answer. Unfortunately, this returns a null as well :-( . I checked out the online JavaDocs on why Drawable.createFromStream would return null http://developer.android.com/reference/android/graphics/drawable/Drawable.html#createFromStream%28java.io.InputStream,%20java.lang.String%29 but it is not detailed. I should add that the I know the stream itself is valid as another non-Android application is able to read it and display the image. (I don't have the source for that application). – OceanBlue Apr 11 '11 at 21:03
  • Certainly, this strikes as the most likely possibility, but I have tested & the service is returning image correctly (please see my EDIT in the question). So am flummoxed right now :-( – OceanBlue Apr 12 '11 at 14:26