Color image ignores alpha channel - why and how to fix it?

Here's what I'm trying to do: On the left is a generic, unpainted RGBA image that I created off-screen and cached for speed (it creates very slowly initially, but very quickly, to colorize with any color later, as needed). This is a square image with a circular swirl. Inside the circle, the image has alpha / opacity 1. Outside of the circle, it has alpha / opacity 0. I displayed it here inside the UIView with the background color [UIColor scrollViewTexturedBackgroundColor] . On the right , what happens is when I try to colorize an image by filling in a solid red rectangle above it after setting CGContextSetBlendMode(context, kCGBlendModeColor) .

UncolorizedColorized incorrectly

This is not what I want, and what I expected. Obviously, coloring a completely transparent pixel (for example, an alpha value of 0) leads to a full-color fill color for some strange reason, and not to a transparent one, as I expected.

I really want to:

Colorized corrected

Now, in this particular case, I can set the clipping region to a circle so that the area outside the circle remains untouched - and this is what I did here as a workaround.

But in my application, I also need to be able to colorize arbitrary shapes where I don't know the clipping path / path. One example is to colorize white text by applying a gradient. How it's done? I suspect there must be some way to do this efficiently - and generally, without any weird tracing / cropping tricks - using image masks ... but I still have to find a tutorial on this. Obviously, this is possible because I saw color gradient text in other games.

By the way, what I canโ€™t do is start with a gradient and a clip / clear parts that I donโ€™t need, because (as shown in the example above) my unpainted source images are usually shades of gray and not pure white. So I really need to start with an unpainted image and then colorize it.

ps - kCGBlendModeMultiply also has the same weaknesses / weaknesses / features when it comes to coloring partially transparent images. Does anyone know why Apple decided to do it this way? As if the Quartz coloring code treats RGBA (0,0,0,0) as RGBA (0,0,0,1), i.e. completely ignores and destroys the alpha channel.

+4
source share
1 answer

One approach you can take is to create a mask from the original image and then call the CGContextClipToMask () method before making the image with the multiplier set. Here is the CoreGraphics code that will set the mask before drawing the image in color.

  CGContextRef context = [frameBuffer createBitmapContext]; CGRect bounds = CGRectMake( 0.0f, 0.0f, width, height ); CGContextClipToMask(context, bounds, maskImage.CGImage); CGContextDrawImage(context, bounds, greyImage.CGImage); 

Taking the source image and creating a maskImage will be a bit more difficult part. What you can do for this is to write a loop that will check each pixel and write a black or white pixel as a mask value. If the original pixel of the image is completely transparent, then write a black pixel, otherwise write a white pixel. Note that the mask value will be a 24BPP image. Here is the code that will give you the right idea.

  uint32_t *inPixels = (uint32_t*) MEMORY_ADDR_OF_ORIGINAL_IMAGE; uint32_t *maskPixels = malloc(numPixels * sizeof(uint32_t)); uint32_t *maskPixelsPtr = maskPixels; for (int rowi = 0; rowi < height; rowi++) { for (int coli = 0; coli < width; coli++) { uint32_t inPixel = *inPixels++; uint32_t inAlpha = (inPixel >> 24) & 0xFF; uint32_t cval = 0; if (inAlpha != 0) { cval = 0xFF; } uint32_t outPixel = (0xFF << 24) | (cval << 16) | (cval << 8) | cval; *maskPixelsPtr++ = outPixel; } } 

Of course, you will need to fill in all the details and create graphic contexts and so on. But the general idea is to simply create your own mask to filter the drawing of red parts around the outer circle.

+1
source

Source: https://habr.com/ru/post/1236045/


All Articles