Search code examples
androidbitmapfactory

BitmapFactory.getByteArray only works if the byte array come from storage


I'm trying to create a program that processes images directly from the Camera2 preview, and I keep running into a problem when it comes to actually processing the incoming images.

In my OnImageAvailableListener.onImageAvailable() callback, I'm getting an ImageReader object, from which I acquireNextImage() and pass that Image object into my helper function. From there, I convert it into a byte array, and attempt to do the processing. Instead, every time I get to the part where I convert it to Bitmap, the BitmapFactory.getByteArray returns null, even though the byte array is a properly-formatted JPEG.

private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
        = new ImageReader.OnImageAvailableListener() {
    @Override
    public void onImageAvailable(ImageReader imageReader) {
        Image image = imageReader.acquireNextImage();
        ProcessBarcode(image);
        image.close();
    }
};

private void ProcessBarcode(Image image) {
    ByteBuffer buffer = image.getPlanes()[0].getBuffer();
    int bufferSize = buffer.remaining();
    byte[] bytes = new byte[bufferSize];
    buffer.get(bytes);

    FileOutputStream output = null;
    try {
        output = new FileOutputStream(mFile);
        output.write(bytes);
        output.close();
    } catch (IOException e) {
        // Do something clever
    }

    // This call FAILS
    //Bitmap b = BitmapFactory.decodeByteArray(bytes, 0, buffer.remaining(), o);

    // But this call WORKS?
    Bitmap b = BitmapFactory.decodeFile(mFile.getAbsolutePath());

    detector = new BarcodeDetector.Builder(getActivity())
            .setBarcodeFormats(Barcode.EAN_13 | Barcode.ISBN)
            .build();

    if (b != null) {
        Frame isbnFrame = new Frame.Builder().setBitmap(b).build();
        SparseArray<Barcode> barcodes = detector.detect(isbnFrame);

        if (barcodes.size() != 0) {
            Log.d("Barcode decoded: ",barcodes.valueAt(0).displayValue);
        }
        else {
            Log.d(TAG, "No barcode detected");
        }
    }
    else {
        Log.d(TAG, "No bitmap detected");
    }
}

The ImageReader is set up like:

mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(), ImageFormat.JPEG, 2);
mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);

Basically what I see is that if I use the byte array directly without first saving it to the internal memory, the camera preview is fast and snappy, although the Bitmap is always null so I'm not actually performing any processing. If I save the byte array to the memory, then I get maybe 2-3fps, but the processing works as I'm intending.


Solution

  • After the call to buffer.get(bytes), buffer.remaining() will return 0, since you just read through the whole ByteBuffer. remaining() tells you how many bytes are left between your current position and the limit of the buffer, and calls to get() move the position forward by the number of bytes read.

    Therefore, when you do decodeByteArray(bytes,0, buffer.remaining(), 0), you don't actually decode any bytes.

    If you try decodeByteArray(bytes, 0, bytes.length, 0), does it work?