Search code examples
iosuiviewuiimagetransparency

Transparency issue - when converting UIView to UIImage


I want to create an UIImage object from a UIView. The view is NOT opaque. for that i'm using the following code:

+ (UIImage *) imageWithView:(UIView *)view 
{     
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, [[UIScreen mainScreen] scale]);     
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];     
    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();  
    UIGraphicsEndImageContext();     
    return img; 
}  

But for some reason instead of transparent background i'm getting a image with black background. I already tried to set the "opaque" parameter in UIGraphicsBeginImageContextWithOptions to NO but with no different results.

Any suggestion?

(Similar question CGContext transparency problem with no answer)


Solution

  • I'm pretty sure you can't define a transparency when creating UIImages like this - you could mask your UIImageView which uses the image though.

    Something like the following functions allow for this type of operation:

    // handles img masking operation
    CGImageRef CopyImageAndAddAlphaChannel(CGImageRef sourceImage) {
        CGImageRef retVal = NULL;
    
        size_t width = CGImageGetWidth(sourceImage);
        size_t height = CGImageGetHeight(sourceImage);
    
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
        CGContextRef offscreenContext = CGBitmapContextCreate(NULL, width, height, 
                                                              8, 0, colorSpace, kCGImageAlphaPremultipliedFirst);
    
        if (offscreenContext != NULL) {
            CGContextDrawImage(offscreenContext, CGRectMake(0, 0, width, height), sourceImage);
    
            retVal = CGBitmapContextCreateImage(offscreenContext);
            CGContextRelease(offscreenContext);
        }
    
        CGColorSpaceRelease(colorSpace);
    
        return retVal;
    }
        // png masks can mask png, gif or jpg...
    - (UIImage*)maskImage:(UIImage *)image withMask:(UIImage *)maskImage 
    {
        CGImageRef maskRef = maskImage.CGImage;
        CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
                                            CGImageGetHeight(maskRef),
                                            CGImageGetBitsPerComponent(maskRef),
                                            CGImageGetBitsPerPixel(maskRef),
                                            CGImageGetBytesPerRow(maskRef),
                                            CGImageGetDataProvider(maskRef), NULL, false);
    
        CGImageRef sourceImage = [image CGImage];
        CGImageRef imageWithAlpha = sourceImage;
        //add alpha channel for images that don't have one (ie GIF, JPEG, etc...)
        //this however has a computational cost
        if ((CGImageGetAlphaInfo(sourceImage) == kCGImageAlphaNone) || (CGImageGetAlphaInfo(sourceImage) == kCGImageAlphaNoneSkipFirst)) 
        { 
            imageWithAlpha = CopyImageAndAddAlphaChannel(sourceImage);
        }
    
        CGImageRef masked = CGImageCreateWithMask(imageWithAlpha, mask);
        CGImageRelease(mask);
    
        //release imageWithAlpha if it was created by CopyImageAndAddAlphaChannel
        if (sourceImage != imageWithAlpha) 
        {
            CGImageRelease(imageWithAlpha);
        }
    
        UIImage* retImage = [UIImage imageWithCGImage:masked];
        CGImageRelease(masked);
    
        return retImage;
    }
    

    You can than call it like this:

    UIImage *imgMasked = [self maskImage:[UIImage imageNamed:@"full_image.png"] withMask:[UIImage imageNamed:@"masked_image.png"]];
    

    masked_image.png needs to be an alpha channeled image which will cut out your black bg.