Issue in checking UIImage have alpha (Transparent)

2019-06-22 07:26发布

问题:

I'm checking that image have transparent area (alpha) or not. Bashed on that I have to change the color of UIImage

I have implement the below method to check the image have alpha or not.

- (BOOL) checkAlpha  : (UIImage*) image
{
    for(int x = 0; x <  image.size.width ; x++)
    {
        for(int y = 0; y < image.size. height; y++)
        {
            CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
            const UInt8* data = CFDataGetBytePtr(pixelData);

            int pixelInfo = ((image.size.width  * y) + x ) * 4; // The image is png

            UInt8 red = data[pixelInfo];         // If you need this info, enable it
            UInt8 green = data[(pixelInfo + 1)]; // If you need this info, enable it
            UInt8 blue = data[pixelInfo + 2];    // If you need this info, enable it
            UInt8 alpha = data[pixelInfo + 3];     // I need only this info for my maze game
            CFRelease(pixelData);

            UIColor* color = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];

            DLog(@"color : %@",color);
            DLog(@"alpha : %hhu",alpha)

            if (alpha)
                return YES;     // display original image from url.
            else
                return NO;      // apply brand color here.
        }
    }
    return YES;
}

This method is working fine but for some image it is creating issue. See the below image:


For above image alpha return 0;


And for above 2 images alpha have some value.

All 3 images have same white background. For the first image also should have some alpha. it should not be 0. Please guide me out on this ? is there any code error in my method or what?

回答1:

Rewrite @Hitarth's answer in Swift4:

extension UIImage {
  public func isTransparent() -> Bool {
    guard let alpha: CGImageAlphaInfo = self.cgImage?.alphaInfo else { return false }
    return alpha == .first || alpha == .last || alpha == .premultipliedFirst || alpha == .premultipliedLast
  }
}


回答2:

Finally find out the solution for the current images which are displaying on the question. I want to find out that UIImage have alpha Channel or not.

- (BOOL)hasAlpha : (UIImage*) img
{
    CGImageAlphaInfo alpha = CGImageGetAlphaInfo(img.CGImage);
    return (
            alpha == kCGImageAlphaFirst ||
            alpha == kCGImageAlphaLast ||
            alpha == kCGImageAlphaPremultipliedFirst ||
            alpha == kCGImageAlphaPremultipliedLast
            );

}

This hasAlpha method is working fine in this case.

For More info : Check out this link



回答3:

For what it's worth, I tried downloading your images, right clicking and picking 'get info'. The info says the images have no alpha channel, so I would start by getting new versions of these images that do have alpha.



回答4:

Run on all the points on an image \ layer and check for alpha channel existence like so:

 UIColor *pixelColor = [SSAlphaPass colorOfPoint:point withLayer:self.layer];
    if(CGColorGetAlpha(pixelColor.CGColor))
    {
        return YES;
    }

    return NO;

+ (UIColor *) colorOfPoint:(CGPoint)point withLayer:(CALayer*)layer
{
    unsigned char pixel[4] = {0};

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    CGContextRef context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast);

    CGContextTranslateCTM(context, -point.x, -point.y);

    [layer renderInContext:context];

    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);

    //NSLog(@"pixel: %d %d %d %d", pixel[0], pixel[1], pixel[2], pixel[3]);

    UIColor *color = [UIColor colorWithRed:pixel[0]/255.0 green:pixel[1]/255.0 blue:pixel[2]/255.0 alpha:pixel[3]/255.0];

    return color;
}

I wrote a class that detects if a certain pixel is transparent, if that's the case the UIButton, for example, passes the Touch event to its super view. You might find it useful.



回答5:

First off, your call to CGDataProviderCopyData() is inside the loop, so it going to be shockingly slow. Second, your code is not going to work with different input PNG image types. The only way to make it work properly is to render the input image into a pixel buffer and then examine the output once flattened out into plain pixels.