How to get real RGBA or ARGB color values ​​without preliminary multiplexed alpha?

I am creating a raster image context using CGBitmapContextCreatewith an option kCGImageAlphaPremultipliedFirst.

I made a 5 x 5 test image with some primary colors (pure red, green, blue, white, black), some mixed colors (i.e. purple) in combination with some alpha options. Each time the alpha component is not 255, the color value is incorrect.

I found that I can recount the color when I do something like:

almostCorrectRed = wrongRed * (255 / alphaValue);
almostCorrectGreen = wrongGreen * (255 / alphaValue);
almostCorrectBlue = wrongBlue * (255 / alphaValue);

But the problem is that my calculations are sometimes disabled by 3 or even more. So, for example, I get a value of 242 instead of 245 for green, and I'm 100% sure that it should be exactly 245. Alpha - 128.

Then, for the same color with different alpha opacity in the PNG bitmap, I get alpha = 255 and green = 245, as it should be.

If alpha is 0, then red, green and blue are also equal to 0. Here, all data is lost, and I can not determine the color of the pixel.

How can I avoid or cancel this alltogether alpha pre-multiplication so that I can change the pixels in my image based on true RGB pixel values, as it was when the image was created in Photoshop? How to restore the original values ​​for R, G, B and A?


Background information (maybe not needed for this question):

, : UIImage, , , , . . . ( , 255), , R, G, B , Alpha , . , . . Alpha , R G B .

+5
3

:

  • 245 * (128/255) = 122,98
  • 122.98 = 122
  • 122 * (255/128) = 243.046875

, 242 243, , , .

. 2D , .

: ( , PNG, , TIFF). , , ; .

- , , . , (), , .

+5

. ( 8 ).

( ), ( ). , , , .

0

, CoreGraphics, . , , , , , CoreGraphics , , . , , , mult 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;
}

github.

, , "", . , , premultiply. , (, CoreGraphics OSX). , , .

0

All Articles