本文介绍了对位图中的像素值感到困惑(使用setPixel预乘颜色)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法解释这一点(Eclipse调试屏幕截图):

I cannot explain this (screenshot from Eclipse debug):

(0,0)处的像素没有为其设置的值!
所有其他像素都很好,它们的值确实与分配给它们的值相同.

Pixel at (0,0) does not have the values it was set for!
All other pixels are fine, they do have the same value they were assigned to.

编辑我做了一些进一步的挖掘,setPixel的代码调用了一个本机函数:

EDITI did some more digging, and the code for setPixel is calling a native function:

1391    public void setPixel(int x, int y, int color) {
1392        checkRecycled("Can't call setPixel() on a recycled bitmap");
1393        if (!isMutable()) {
1394            throw new IllegalStateException();
1395        }
1396        checkPixelAccess(x, y);
1397        nativeSetPixel(mNativeBitmap, x, y, color, mIsPremultiplied);
1398    }

所以我以不同的值运行setPixel(0,0),从对setPixel(0,1)可以使用的值开始.
首先,我只更改了其中一个论点.结论是alpha值是罪魁祸首,但不确定确切如何.我尝试了许多其他alpha值,似乎0xB0左右及以上的结果又恢复了.
我在其他像素上尝试了相同的值,但问题不取决于像素坐标,其他像素也无法使用.问题似乎与数据有关.

so I run setPixel(0,0) with different values, starting with the one that was OK for setPixel(0,1).
First I changed only one of the arguments. The conclusion is that the alpha value is the culprit, but not sure exactly how. I tried a lot of other alpha values and it seems that around 0xB0 and up the results are coming back OK.
I tried the same values on other pixels and the problem is not dependent on the pixel coordinates, it fails as well for others. The problem seems to be data dependent.

    source.setPixel(0, 0, Color.argb(0x40, 0x1A, 0x11, 0x12));
    int sp00 = source.getPixel(0, 0); // sp00   1075580948 [0x401c1014] BAD

    source.setPixel(0, 0, Color.argb(0xFE, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   -16781602 [0xfeffeede]  OK!
    source.setPixel(0, 0, Color.argb(0x40, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   1090514911 [0x40ffefdf] BAD
    source.setPixel(0, 0, Color.argb(0xFE, 0x1A, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   -31789346 [0xfe1aeede]  OK!
    source.setPixel(0, 0, Color.argb(0xFE, 0xFF, 0x11, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   -16838178 [0xfeff11de]  OK!
    source.setPixel(0, 0, Color.argb(0xFE, 0xFF, 0xEE, 0x12));
    sp00 = source.getPixel(0, 0); // sp00   -16781806 [0xfeffee12]  OK!

    source.setPixel(0, 0, Color.argb(0x00, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   0 [0x0] Strange, why Color has to police the alpha value?
    source.setPixel(0, 0, Color.argb(0x10, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   285208543 [0x10ffefdf]  BAD
    source.setPixel(0, 0, Color.argb(0x20, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   553643999 [0x20ffefdf]  BAD
    source.setPixel(0, 0, Color.argb(0x30, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   822079455 [0x30ffefdf]  BAD
    source.setPixel(0, 0, Color.argb(0x50, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   1358950367 [0x50ffefdf] BAD
    source.setPixel(0, 0, Color.argb(0x60, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   1627385823 [0x60ffefdf] BAD
    source.setPixel(0, 0, Color.argb(0x70, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   1895821279 [0x70ffefdf] BAD
    source.setPixel(0, 0, Color.argb(0x80, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   -2130711075 [0x80ffeddd] BAD but change of pattern
    source.setPixel(0, 0, Color.argb(0x90, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   -1862275619 [0x90ffeddd] BAD
    source.setPixel(0, 0, Color.argb(0xA0, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   -1593840162 [0xa0ffedde] BAD but change of pattern again
    source.setPixel(0, 0, Color.argb(0xB0, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   -1325404450 [0xb0ffeede] OK!
    source.setPixel(0, 0, Color.argb(0xC0, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   -1056968994 [0xc0ffeede] OK!
    source.setPixel(0, 0, Color.argb(0xD0, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   -788533538 [0xd0ffeede] OK!
    source.setPixel(0, 0, Color.argb(0xE0, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   -520098082 [0xe0ffeede] OK!
    source.setPixel(0, 0, Color.argb(0xF0, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   -251662626 [0xf0ffeede] OK!

    source.setPixel(0, 0, Color.argb(0xA7, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   -1476399395 [0xa7ffeedd] BAD
    source.setPixel(0, 0, Color.argb(0xA3, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   -1543508258 [0xa3ffeede] OK!
    source.setPixel(0, 0, Color.argb(0xA1, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   -1577062690 [0xa1ffeede] OK!
    source.setPixel(0, 0, Color.argb(0xAB, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   -1409290274 [0xabffefde] BAD
    source.setPixel(0, 0, Color.argb(0xA9, 0xFF, 0xEE, 0xDE));
    sp00 = source.getPixel(0, 0); // sp00   -1442844962 [0xa9ffeede] OK!

推荐答案

好吧,我或多或少地发现了正在发生的事情.
它被称为预乘Alpha",而api19之前的位图不提供任何控制此功能的方法,它们在默认情况下是预乘的,因此无法更改.
在api19上,有两种用于 Bitmap 的新方法: isPremultiplied() setPremultiplied(boolean)
根据新文档:

Well, more or less I found what is happening.
It is called "pre-multiplied Alpha" and Bitmaps before api19 do not offer any way to control this feature, they are premultiplied by default and this cannot be changed.
On api19 there are 2 new methods to Bitmap: isPremultiplied() and setPremultiplied(boolean)
According to the new doc:

这篇文章和这则其他帖子提供了更多说明.据此,更多测试显示:

Also this post and this other post give some more explanation. According to this, some more tests show:

    Bitmap source = Bitmap.createBitmap(2, 2, Config.ARGB_8888);
    source.setPixel(0, 0, Color.argb(0x02, 0x10, 0x20, 0x30));
    source.setPixel(0, 1, Color.argb(0x03, 0x10, 0x20, 0x30));
    source.setPixel(1, 0, Color.argb(0x05, 0x78, 0x96, 0x64));
    source.setPixel(1, 1, Color.argb(128, 255, 200, 150));

    int sp00 = source.getPixel(0, 0); // sp00   33554432 [0x2000000]
    int sp01 = source.getPixel(0, 1); // sp01   50331733 [0x3000055]
    int sp10 = source.getPixel(1, 0); // sp10   90610022 [0x5669966]
    int sp11 = source.getPixel(1, 1); // sp11   -2130720875 [0x80ffc795]

对于较低的颜色值,四舍五入会导致信息丢失(请参见上面的sp00).
另外,对于较低的值,alpha本身的值不会恢复为原始值.
最重要的是,给定的公式无法解释我看到的值.

For lower color values the rounding causes the info to be lost (see sp00 above).
Also, for lower values, the value of alpha itself is not retrieved to the original.
On top of this, the given formulas do not explain the values I see.

最后要使用未修改的像素,我现在使用以下代码设置位图像素:

Finally to use unmodified pixels I now use this code to set the Bitmap pixles:

    Bitmap source = Bitmap.createBitmap(2, 2, Config.ARGB_8888);
    IntBuffer data = IntBuffer.wrap(new int[] {
            Color.argb(0x06, 0xff, 0xa0, 0x8d),
            Color.argb(0x2a, 0xab, 0xce, 0x9f),
            Color.argb(0x8f, 0xfe, 0x05, 0x18),
            Color.argb(0xff, 0xc8, 0xcf, 0xd4)
    });
    source.copyPixelsFromBuffer(data);

并获取我使用的像素:

    IntBuffer sourceData = IntBuffer.allocate(4);
    source.copyPixelsToBuffer(sourceData);

使用这些方法不会将颜色预乘.

Using these methods do not premultiply the color.

这篇关于对位图中的像素值感到困惑(使用setPixel预乘颜色)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-01 07:02