Question

How can I fill the non-transparent areas of a PNG UIImage with a linear gradient? I'd like to reuse a PNG shape for MKAnnotationViews, but change the gradient per annotation's properties.

Était-ce utile?

La solution

To use an image as a mask for a gradient (i.e. to have a gradient in the shape of the non-transparent pixels of your image), you can:

  • create a simple view with a gradient (you can either create a simple UIView and use the addGradientLayerToView shown below to give it a gradient or you can create the gradient PNG in advance and add it to your bundle).

  • apply your PNG as a mask to that gradient view:

    UIImage *mask = [UIImage imageNamed:@"mask.png"];
    CALayer *maskLayer = [CALayer layer];
    maskLayer.frame = CGRectMake(0, 0, mask.size.width, mask.size.height);
    maskLayer.contents = (id)[mask CGImage];
    gradientViewToMask.layer.mask = maskLayer;
    

To apply a gradient to the transparent pixels, you can either:

  1. Create a new image with a gradient:

    - (UIImage *)imageWithGradient:(UIImage *)image
    {
        UIGraphicsBeginImageContextWithOptions(image.size, NO, 1.0);
    
        CGContextRef context = UIGraphicsGetCurrentContext();
    
        size_t locationCount = 2;
        CGFloat locations[2] = { 0.0, 1.0 };
        CGFloat components[8] = { 0.0, 0.8, 0.8, 1.0,   // Start color
                                  0.9, 0.9, 0.9, 1.0 }; // End color
    
        CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
    
        CGGradientRef gradient = CGGradientCreateWithColorComponents (colorspace, components, locations, locationCount):
    
        CGPoint startPoint = CGPointMake(0.0, 0.0);
        CGPoint endPoint   = CGPointMake(0.0, image.size.height);
        CGContextDrawLinearGradient (context, gradient, startPoint, endPoint, 0);
    
        CGContextTranslateCTM(context, 0, image.size.height);
        CGContextScaleCTM(context, 1.0, -1.0);
    
        CGContextDrawImage(context, CGRectMake(0.0, 0.0, image.size.width, image.size.height), [image CGImage]);
    
        UIImage *gradientImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        CGGradientRelease(gradient);
        CGColorSpaceRelease(colorspace);
    
        return gradientImage;
    }
    
  2. You can also add a CAGradientLayer to a view and then add the UIImageView as a subview of that view.

    - (void)addGradientLayerToView:(UIView *)view
    {
        CAGradientLayer *gradient = [CAGradientLayer layer];
        gradient.frame = view.bounds;
        gradient.colors = @[(id)[[UIColor colorWithRed:0.0 green:0.8 blue:0.8 alpha:1.0] CGColor],
                            (id)[[UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1.0] CGColor]];
        [view.layer insertSublayer:gradient atIndex:0];
    }
    

    Note, you have to #import <QuartzCore/QuartzCore.h> as well as add the QuartzCore framework to your project.

Autres conseils

I ended up hacking together some bits of Rob's code and an extension to UIImage I found at http://coffeeshopped.com/2010/09/iphone-how-to-dynamically-color-a-uiimage

+ (UIImage *)imageNamed:(NSString *)name withGradient:(CGGradientRef)gradient
{
    // load the image
    UIImage *img = [UIImage imageNamed:name];

    // begin a new image context, to draw our colored image onto
    UIGraphicsBeginImageContextWithOptions(img.size, NO, [[UIScreen mainScreen] scale]);

    // get a reference to that context we created
    CGContextRef context = UIGraphicsGetCurrentContext();

    // translate/flip the graphics context (for transforming from CG* coords to UI* coords
    CGContextTranslateCTM(context, 0, img.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    // set the blend mode to overlay, and the original image
    CGContextSetBlendMode(context, kCGBlendModeOverlay);
    CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);

    // set a mask that matches the shape of the image, then draw (overlay) a colored rectangle
    CGContextClipToMask(context, rect, img.CGImage);
    CGContextAddRect(context, rect);

    //gradient
    CGPoint startPoint = CGPointMake(0.0, img.size.height);
    CGPoint endPoint   = CGPointMake(0.0, 0.0);
    CGContextDrawLinearGradient (context, gradient, startPoint, endPoint, 0);

    // generate a new UIImage from the graphics context we drew onto
    UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    CGGradientRelease(gradient);

    //return the color-burned image
    return coloredImg;

}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top