【问题标题】:How to get a Bitmap from a raw image如何从原始图像中获取位图
【发布时间】:2011-04-11 19:57:52
【问题描述】:

我正在从网络读取原始图像。此图像已由图像传感器读取,而不是从文件中读取。

以下是我对图像的了解:
~ 高度和宽度
~ 总大小(以字节为单位)
~ 8 位灰度
~ 1 字节/像素

我正在尝试将此图像转换为位图以显示在图像视图中。

这是我尝试过的:

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

decodeByteArray 返回 null,因为它无法解码我的图像。

我也尝试直接从输入流中读取它,而不是先将其转换为字节数组:

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

这也返回 null

我在此论坛和其他论坛上进行了搜索,但找不到实现此目的的方法。

有什么想法吗?

编辑:我应该补充一点,我做的第一件事是检查流是否真的包含原始图像。我使用其他应用程序 `(iPhone/Windows MFC) 做到了这一点,他们能够读取并正确显示图像。我只需要想办法在 Java/Android 中做到这一点。

【问题讨论】:

    标签: android android-image


    【解决方案1】:

    Android 不支持灰度位图。因此,首先,您必须将每个字节扩展为 32 位 ARGB int。 Alpha 为 0xff,R、G 和 B 字节是源图像字节像素值的副本。然后在该数组的顶部创建位图。

    另外(参见 cmets),设备似乎认为 0 是白色,1 是黑色 - 我们必须反转源位。

    所以,我们假设源图像位于名为 Src 的字节数组中。代码如下:

    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:感谢您的回答。我尝试了你的建议。我得到一个运行时异常。根据 logcat “缓冲区不足以容纳像素”。我正在使用图像的宽度和高度创建位图。
    • @OceanBlue:消息表明位缓冲区的长度小于 4*Width*Height 字节。检查是不是。 ARGB_888 是每像素 4 字节的格式。
    • @Seva Alekseyev:我确定位缓冲区是 Width*Height 字节长。图像是每像素 1 个字节的格式。因此,即使我创建一个 4 倍大小的字节数组,图像也会存储在它的前 1/4 部分。您会碰巧知道 Android 中的任何“每像素 1 个字节”格式吗?
    • @Seva Alekseyev:感谢您一直以来的支持。我确实看到了一张图片(Yoohoo !!!)。出于某种奇怪的原因,它绘制的是青色背景上的白线,而不是白色背景上的黑线。如果您碰巧知道原因,我将不胜感激。
    • 您可能使用了我的代码 sn-p 的第一个版本,其中有一个错字。最后一个循环行是 1 而不是 3,所以红色位没有初始化。
    【解决方案2】:

    一旦我做了这样的事情来解码从相机预览回调中获得的字节流:

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

    试一试。

    【讨论】:

    • 感谢您的回答。第一个参数“imageBytes”包含什么?在我在在线 Javadocs 中看到的所有 Bitmap.createBitmap(...) 的重载版本中,没有一个将字节数组作为参数。
    【解决方案3】:
    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.
    }
    

    转换循环将8位图像转换为RGBA可能需要很多时间,640x800图像可能需要500ms以上...更快的解决方案是使用ALPHA8格式的位图并使用滤色器:

    //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);
    

    【讨论】:

      【解决方案4】:

      使用 Drawable 从流创建。以下是使用 HttpResponse 的方法,但您可以随心所欲地获取输入流。

        InputStream stream = response.getEntity().getContent();
      
        Drawable drawable = Drawable.createFromStream(stream, "Get Full Image Task");
      

      【讨论】:

      • 感谢您的回答。不幸的是,这也返回了一个 null :-(。我查看了在线 JavaDocs 为什么 Drawable.createFromStream 会返回 null developer.android.com/reference/android/graphics/drawable/… 但它没有详细说明。我应该补充一点,我知道流本身作为另一个非有效-Android 应用程序能够读取它并显示图像。(我没有该应用程序的源代码)。
      • 当然,这是最有可能的可能性,但我已经测试过并且服务正在正确返回图像(请参阅我在问题中的编辑)。所以我现在很困惑:-(
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-08
      • 1970-01-01
      • 1970-01-01
      • 2021-09-06
      • 2018-03-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多