【问题标题】:byte array to bitmap returns null字节数组到位图返回 null
【发布时间】:2021-01-21 00:20:19
【问题描述】:

我有一个小程序,它采用 Chair.jpg 并将其转换为位图。这样做的原因是将像素的颜色类型更改为BGR_888的格式(我从this stack overflow post得到的。)

但是位图为空。我相信是因为这个原因D/skia: --- Failed to create image decoder with message 'unimplemented'。在网上看,可能是因为我需要压缩这个?我不知道。谁能帮我理解一下?

public class MainActivity extends AppCompatActivity {

    TextView textView;
    ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView = findViewById(R.id.imageView);
        textView = findViewById(R.id.textView);

        Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.chair);
        imageView.setImageBitmap(b);

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

        Log.d("bitmap height", String.valueOf(height));
        Log.d("bitmap width", String.valueOf(width));
        Bitmap.Config config = b.getConfig();
        Log.d("b color format", String.valueOf(config));

        byte[] newImage = getImagePixels(b);
        Log.d("getImagePixels Result", String.valueOf(newImage));

        boolean b2 = isNewBitmapNull(newImage);
        Log.d("is my new bitmap null:",String.valueOf(b2));


    }

    /// <summary>
    /// function getImagePixels
    /// Purpose: Given the bitmap image return the converted 4 byte ARGB to 3 byte BGR
    /// </summary>
    /// <param name="image"> Bitmap image object </param>

    public byte[] getImagePixels(Bitmap image) {
        // calculate how many bytes our image consists of
        int bytes = image.getByteCount();
        // Create a new buffer
        ByteBuffer buffer = ByteBuffer.allocate(bytes);
        // Move the byte data to the buffer
        image.copyPixelsToBuffer(buffer);

        // Get the underlying array containing the data.
        byte[] temp = buffer.array();

        // Allocate for 3 byte BGR
        byte[] pixels = new byte[(temp.length / 4) * 3];

        // Copy pixels into place
        for (int i = 0; i < (temp.length / 4); i++) {
            pixels[i * 3] = temp[i * 4 + 3];     // B
            pixels[i * 3 + 1] = temp[i * 4 + 2]; // G
            pixels[i * 3 + 2] = temp[i * 4 + 1]; // R

            // Alpha is discarded
        }
        Log.d("check if it is array", String.valueOf(pixels.getClass().isArray()));
        Log.d("array object type", String.valueOf(pixels.getClass()));
        Log.d("array length", String.valueOf(pixels.length));
        return pixels;
    }

    public static byte[] convertBitmapToByteArrayUncompressed(Bitmap bitmap){
        ByteBuffer byteBuffer = ByteBuffer.allocate(bitmap.getByteCount());
        bitmap.copyPixelsToBuffer(byteBuffer);
        byteBuffer.rewind();
        return byteBuffer.array();
    }

    /// <summary>
    /// function copyPixelsToBitmap
    /// Purpose: Given the pixel data return a bitmap of size [?,?],PixelFormat=24BGR
    /// </summary>
    /// <param name="pixels"> Byte array with pixel data </param>
    public Bitmap copyPixelsToBitmap(byte[] pixels){
        //Here create the Bitmap to the know height, width and format
        Bitmap bmp = BitmapFactory.decodeByteArray(pixels, 0, pixels.length);

        //Return the bitmap
        return bmp;
    }

    /// <summary>
    /// function isNewBitmapNull
    /// Purpose: Given the pixel data return T/F is the bitmap was created
    /// </summary>
    /// <param name="pixels"> Byte array with pixel data </param>
    public boolean isNewBitmapNull(byte[] pixels){
        //BitmapFactory.Options options = new BitmapFactory.Options();
        //options.inMutable = true;
        Bitmap bmp = BitmapFactory.decodeByteArray(pixels, 0, pixels.length);
        if (bmp == null)
            return true;


        return false;
    }
}

对于 isNewBitMapNull 方法,我也尝试添加 BitMapFactory 选项,但仍然得到一个空位图:

//BitmapFactory.Options options = new BitmapFactory.Options();
//options.inMutable = true;
Bitmap bmp = BitmapFactory.decodeByteArray(pixels, 0, pixels.length, options);

这是输出:

D/bitmap height: 1260 
D/bitmap width: 1260
D/b color format: ARGB_8888
D/check if it is array: true
D/array object type: class [B
D/array length: 4762800
D/getImagePixels Result: [B@5a36e09
D/skia: --- Failed to create image decoder with message 'unimplemented'
D/is my new bitmap null:: true

【问题讨论】:

  • 您对 BGR 的转换要么是错误的,要么取决于平台的字节序,因为 temp[i * 4 + 3] 在我的情况下返回 alpha 通道。

标签: java android bitmap android-bitmap bitmapfactory


【解决方案1】:

您似乎正在尝试创建一个每像素 3 个字节的位图,但在 Android 中这是不可能的,因为位图支持 1, 2, 4 or 8 bytes per pixel

这就是为什么您需要使用受支持的像素格式创建新位图的原因。但是使用BitmapFactory.decodeByteArray 不起作用,因为它会从压缩的图像数据(例如存储在 .jpg 文件中的数据)创建位图。但是你有一组原始像素值(未压缩)。

虽然可以选择压缩图像然后使用decodeByteArray 读取它,但您需要自己实现BGR_888 的压缩或使用第3 方库。更简单的方法是将BGR_888 转换回ARGB_8888 并根据这些数据创建位图:

val temp = IntArray(width * height)

for (i in 0 until width * height) {
    val red = pixels[i * 3 + 2].toInt() and 0xff
    val green = pixels[i * 3 + 1].toInt() and 0xff
    val blue = pixels[i * 3].toInt() and 0xff
    temp[i] = Color.rgb(red, green, blue)
}
return Bitmap.createBitmap(temp, width, height, Bitmap.Config.ARGB_8888)

Java 版本:

int[] temp = new int[width * height];

for (int i = 0; i < width * height; ++i) {
    int red = (int)pixels[i * 3 + 2] & 0xff;
    int green = (int)pixels[i * 3 + 1] & 0xff;
    int blue = (int)pixels[i * 3] & 0xff;
    temp[i] = Color.rgb(red, green, blue);
}
return Bitmap.createBitmap(temp, width, height, Bitmap.Config.ARGB_8888);

【讨论】:

  • 嗨@fdermishin :) 我有点明白你在说什么。我实际上需要 BGR_888 格式而不是 ARGB_8888 :P 所以为了这个工作,我需要压缩我的原始像素数组?然后将其发送到位图? (你提到它不可能,因为它的 3 BPP 而不是 4 BPP 例如)......那么有什么选择?
  • 这取决于您要达到的目标。你打算如何使用 BGR_888 格式?您是否要处理 BGR_888 像素的数组,然后使用 Bitmap 类来显示图像?或者某些库是否只接受 BGR_888 格式的位图?或者您可能正在尝试减少位图的内存消耗?
  • 像素格式只是一个内部实现细节,BGR_888 和 ARGB_8888(alpha 等于 1)都存储相同的信息,因此可以用一种格式完成的所有事情都可以用另一种格式完成.因此,除非有依赖于位图内部细节的特定要求,否则像素格式无关紧要。
  • 感谢@fdermishin 提供的信息,我正在使用自定义对象检测库,其中通道顺序需要 BGR。
  • 最终,jpeg 图像需要转换为 BGR_888 格式才能使库正常工作。这就是为什么将 jpeg 图像转换为位图,然后转换为字节数组的原因。因此,在获得原始像素并使其可见之后,我可以显示图像。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-28
  • 1970-01-01
  • 2018-05-31
  • 2012-09-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多