Android SetPixels() 方法解释和示例?

4

我正在尝试在我的Android应用中将可变位图的一部分像素设置为不同的颜色。不幸的是,我无法正确使用setPixels()方法。我一直收到ArrayOutOfBoundsExceptions异常。我认为这可能与步幅有关,但我真的不确定。那是我仍然不理解的唯一参数。我看过的唯一其他关于setPixels(不是setPixel)的帖子在这里:drawBitmap() and setPixels(): what's the stride?它没有帮助我。我尝试将步幅设置为0、位图的宽度和位图的宽度减去我要绘制的区域,但它仍然崩溃。下面是我的代码:

public void updateBitmap(byte[] buf, int offset, int x, int y, int width, int height) {
    // transform byte[] to int[]
    IntBuffer intBuf = ByteBuffer.wrap(buf).asIntBuffer();
    int[] intarray = new int[intBuf.remaining()];
    intBuf.get(intarray);                                       

    int stride = ??????
    screenBitmap.setPixels(intarray, offset, stride, x, y, width, height); // crash here

我的位图是可变的,所以我知道问题不在于它。我也确定我的字节数组已经被正确地转换为整数数组。但是我一直收到ArrayOutOfBoundsException异常,我不明白为什么。请帮我解决这个问题。

编辑 - 这是我构造虚假输入的方式:

int width = 1300;
int height = 700;
byte[] buf = new byte[width * height * 4 * 4]; // adding another * 4 here seems to work... why?     
for (int i = 0; i < width * height * 4 * 4; i+=4) {
    buf[i] = (byte)255;
    buf[i + 1] = 3;
    buf[i + 2] = (byte)255;
    buf[i + 3] = 3;         
}
//(byte[] buf, int offset, int x, int y, int width, int height)  - for reference        
siv.updateBitmap(buf, 0, 0, 0, width, height);

所以宽度和高度应该是正确的整数值(至少应该是这样)。编辑2 - 这是创建screenBitmap的原始代码:
public Bitmap createABitmap() {
int w = 1366;
int h = 766;

byte[] buf = new byte[h * w * 4];

for (int i = 0; i < h * w * 4;i+=4) {
        buf[i] = (byte)255;
    buf[i+1] = (byte)255;
    buf[i+2] = 0;
    buf[i+3] = 0;
}

DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);

IntBuffer intBuf = ByteBuffer.wrap(buf).asIntBuffer();  
int[] intarray = new int[intBuf.remaining()];
intBuf.get(intarray);                                           

Bitmap bmp = Bitmap.createBitmap(metrics, w, h, itmap.Config.valueOf("ARGB_8888"));
bmp.setPixels(intarray, 0, w, 0, 0, w, h);
return bmp;
}

在这种情况下似乎可以工作,不确定区别是什么。


步幅应该是宽度。当一维数组被假装成二维数组时,这是你需要向前走的距离,以便下降一行。 - Tatarize
这不起作用,因为setPixels()需要一个int数组。你的4色样本字节数组正在变成各种蓝色。0baaaaaaaarrrrrrrrggggggggbbbbbbbbb。 - Tatarize
3个回答

2

简短

我认为,stride 是以像素为单位包含在图像中的宽度。

详细

从文档中了解到,该算法应该按以下方式工作:

public void setPixels (int[] pixels, 
            int offset, 
            int stride, 
            int x, 
            int y, 
            int width, 
            int height)
    for (int rowIndex = 0; rowIndex < height; rowIndex++) {
        int rowStart = offset + stride * rowIndex; // row position in pixels
        int bitmapY = y + rowIndex; // y position in the bitmap
        for (int columnIndex = 0; columnIndex < width; columnIndex++) {
            int bitmapX = x + columnIndex; // x position in the bitmap
            int pixelsIndex = rowStart + columnIndex; // position in pixels
            setPixel(bitmapX, bitmapY, pixels[pixelsIndex]);

        }
    }
}

对于这些参数,我会执行以下操作,因为它允许您只使用一个像素源并在不同的大小中裁剪不同的图像。如果我有误,请随意纠正算法。

所以,假设您有一个像素宽度像素高度像素的图像。 然后你想要复制一个在像素X像素Y处的宽度高度的部分到一个位于位图X位图Y位置的位图。 这应该是调用:

bitmap.setPixels(
    pixelsWidth * pixelsY + pixelsX, // offset
    pixelsWidth, // stride
    bitmapX, // x
    bitmapY, // y
    width,
    height)

1
可能应该是:

可能应该是:

screenBitmap.setPixels(intarray, 0, width / 4, x, y, width / 4, height);

因为你将字节转换为整数。你的错误是ArrayOutOfBoundsExceptions。请检查大小是否小于intBuf.remaining() = width * height / 4

你的代码在哪一行崩溃了?是在intBuf.remaining()还是screenBitmap.setPixels?另外,你的stride值是多少?它无法显示。 - yushulx
屏幕位图的宽度和高度值是否等于其尺寸大小? - yushulx
我的代码在bitmap.setPixels(...)处崩溃。我已经尝试了许多关于stride的方法,但似乎都不能处理我通过socket接收到的数据。出于某种原因,当我在虚假数据中添加4倍的像素时,它可以正常工作。我不明白为什么我需要执行height * width * 16来将新部分写入位图以显示我的图像。目前,我通过socket接收到一个20x20像素块的数据。这相当于1600字节(20 x 20像素 x 4字节/像素),我已经验证为400个整数。所以从数字上看,它应该可以工作,但实际上却没有... - Trevor
你的screenBitmap的宽度和高度是多少?你是如何创建它的? - yushulx
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/38077/discussion-between-trevor-and-yushulx - Trevor
显示剩余3条评论

0
如果您想在位图上绘制,最好的方法是放弃这种方法,改用画布(canvas):
Canvas canvas = new Canvas(screenBitmap);

你可以绘制特定的点(如果你想画一个像素),或者其他形状,如矩形、圆形等:
canvas.drawPoint(x, y, paint);

等等

希望这可以帮到你。


我并不试图在位图上绘制。我试图模拟实时视频流,因此我将随着新的图像数据的到来更新位图。所以我不想绘制,我想将像素设置为它们的新值。 - Trevor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接