Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/101.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 如何在没有预乘alpha的情况下获得真实的RGBA或ARGB颜色值?_Iphone_Ios_Ipad_Core Graphics_Quartz 2d - Fatal编程技术网

Iphone 如何在没有预乘alpha的情况下获得真实的RGBA或ARGB颜色值?

Iphone 如何在没有预乘alpha的情况下获得真实的RGBA或ARGB颜色值?,iphone,ios,ipad,core-graphics,quartz-2d,Iphone,Ios,Ipad,Core Graphics,Quartz 2d,我使用kGimageAlphaPremultipledFirst选项创建位图上下文 我用一些主要颜色(纯红、绿、蓝、白、黑)、一些混合颜色(即紫色)以及一些阿尔法变化制作了一张5 x 5的测试图像。每次alpha组件不是255时,颜色值都是错误的 我发现我可以重新计算颜色,比如: almostCorrectRed = wrongRed * (255 / alphaValue); almostCorrectGreen = wrongGreen * (255 / alphaValue); almos

我使用
kGimageAlphaPremultipledFirst
选项创建位图上下文

我用一些主要颜色(纯红、绿、蓝、白、黑)、一些混合颜色(即紫色)以及一些阿尔法变化制作了一张5 x 5的测试图像。每次alpha组件不是255时,颜色值都是错误的

我发现我可以重新计算颜色,比如:

almostCorrectRed = wrongRed * (255 / alphaValue);
almostCorrectGreen = wrongGreen * (255 / alphaValue);
almostCorrectBlue = wrongBlue * (255 / alphaValue);
但问题是,我的计算有时会偏离3甚至更多。例如,我得到的值是242,而不是245,对于绿色,我100%确定它一定是245。阿尔法是128

然后,对于PNG位图中完全相同的颜色和不同的alpha不透明度,我得到alpha=255和green=245

如果alpha为0,则红色、绿色和蓝色也为0。这里所有的数据都丢失了,我无法确定像素的颜色

我怎样才能避免或撤销这个alpha预乘,这样我就可以根据真实的RGB像素值修改图像中的像素,就像在Photoshop中创建图像时那样?如何恢复R、G、B和A的原始值


背景信息(此问题可能不需要):


我正在做的是:我获取一个UIImage,将其绘制到位图上下文中,以便对其执行一些简单的图像处理算法,根据之前的颜色改变每个像素的颜色。没什么特别的。但是我的代码需要真实的颜色。当一个像素是透明的(意味着它的alpha小于255)时,我的算法不应该关心这一点,它应该根据需要修改R、G、B,而alpha保持不变。有时它也会使阿尔法向上或向下移动。但我把它们看作是两个不同的东西。Alpha控制透明度,而RGB控制颜色。

这是积分类型中预乘的一个基本问题:

  • 245*(128/255)=122.98
  • 122.98截断为整数=122
  • 122*(255/128)=243.046875
我不知道为什么你得到的是242而不是243,但这个问题仍然存在,而且α越低,情况就越糟

解决办法是改用。Quartz 2D编程指南提供了以下内容

要点:您需要在创建原始图像时使用浮点(我认为甚至不可能将这样的图像保存为PNG;您可能需要使用TIFF)。一个已经在整数类型中预乘的图像已经失去了该精度;没有办法把它拿回来


零alpha情况就是这种情况的极端版本,以至于连浮点都帮不上忙。任何乘以零(alpha)的值都是零,并且无法从该点恢复原始未乘以的值。

将alpha与整数颜色类型预乘以是一种信息损失操作。数据在量化过程中被破坏(舍入到8位)


由于某些数据被破坏(取整),因此无法恢复精确的原始像素颜色(某些幸运值除外)。您必须先保存photoshop图像的颜色,然后再将其绘制到位图上下文中,并使用原始颜色数据,而不是位图中的倍增颜色数据。

在尝试读取图像数据、使用CoreGraphics将其渲染到另一个图像,然后将结果保存为非预倍增数据时,我遇到了同样的问题。我发现对我有效的解决方案是保存一个表,其中包含CoreGraphics用于将非预乘数据映射到预乘数据的精确映射。然后,通过mult and floor()调用估计原始的预乘值。然后,如果估计值和表查找的结果不匹配,只需检查表中估计值下方的值和估计值上方的值是否完全匹配

// Execute premultiply logic on RGBA components split into componenets.
// For example, a pixel RGB (128, 0, 0) with A = 128
// would return (255, 0, 0) with A = 128

static
inline
uint32_t premultiply_bgra_inline(uint32_t red, uint32_t green, uint32_t blue, uint32_t alpha)
{
  const uint8_t* const restrict alphaTable = &extern_alphaTablesPtr[alpha * PREMULT_TABLEMAX];
  uint32_t result = (alpha << 24) | (alphaTable[red] << 16) | (alphaTable[green] << 8) | alphaTable[blue];
  return result;
}

static inline
int unpremultiply(const uint32_t premultRGBComponent, const float alphaMult, const uint32_t alpha)
{
  float multVal = premultRGBComponent * alphaMult;
  float floorVal = floor(multVal);
  uint32_t unpremultRGBComponent = (uint32_t)floorVal;
  assert(unpremultRGBComponent >= 0);
  if (unpremultRGBComponent > 255) {
    unpremultRGBComponent = 255;
  }

  // Pass the unpremultiplied estimated value through the
  // premultiply table again to verify that the result
  // maps back to the same rgb component value that was
  // passed in. It is possible that the result of the
  // multiplication is smaller or larger than the
  // original value, so this will either add or remove
  // one int value to the result rgb component to account
  // for the error possibility.

  uint32_t premultPixel = premultiply_bgra_inline(unpremultRGBComponent, 0, 0, alpha);

  uint32_t premultActualRGBComponent = (premultPixel >> 16) & 0xFF;

  if (premultRGBComponent != premultActualRGBComponent) {
    if ((premultActualRGBComponent < premultRGBComponent) && (unpremultRGBComponent < 255)) {
      unpremultRGBComponent += 1;
    } else if ((premultActualRGBComponent > premultRGBComponent) && (unpremultRGBComponent > 0)) {
      unpremultRGBComponent -= 1;
    } else {
      // This should never happen
      assert(0);
    }
  }

  return unpremultRGBComponent;
}
//对拆分为组件集的RGBA组件执行预乘逻辑。
//例如,a=128的像素RGB(128,0,0)
//将返回(255,0,0)和A=128
静止的
内联
uint32预乘法线路(uint32红色、uint32绿色、uint32蓝色、uint32阿尔法)
{
const uint8_t*const restrict alphaTable=&extern_alphatableptr[alpha*PREMULT_TABLEMAX];
uint32_t结果=(alpha>16)&0xFF;
if(premultRGBComponent!=premultActualRGBComponent){
if((premultActualRGBComponentpremultRGBComponent)&(unmultRGbComponent>0)){
unmultgbComponent-=1;
}否则{
//这永远不应该发生
断言(0);
}
}
返回unmultgbComponent;
}
您可以在此处找到完整的静态值表


请注意,这种方法不会在对原始未倍增像素进行预倍增时恢复“丢失”的信息。但是,它确实返回最小的未乘像素,一旦再次通过预乘逻辑,该像素将成为预乘像素。当图形子系统仅接受预乘像素(如OSX上的CoreGraphics)时,这非常有用。如果图形子系统只接受预倍增像素,那么最好只存储预倍增像素,因为与未倍增像素相比,占用的空间更少。

附加说明:Xcode另外运行
pngcrush-iphone
以应用iDevice优化,其中之一是预倍增alpha,因此,默认情况下,应用程序中的所有PNG都将被预乘。解决方法是将您不希望被损坏的图像放入文件夹,并将其添加为“文件夹引用”(如果您从嵌入式web服务器提供PNG,则很有用)。我已经成功地将结果四舍五入,使用0.5以上的任何值将结果四舍五入到下一个最高整数,使用低于0.5的任何值将结果四舍五入到较低整数