¿Cómo configurar la opacidad / alfa de un UIImage?

81

Sé que puede hacer esto con un UIImageView, pero ¿se puede hacer con un UIImage? Quiero que la propiedad de matriz de imágenes de animación de un UIImageView sea una matriz de la misma imagen pero con diferentes opacidades. Pensamientos?

Marty
fuente

Respuestas:

122

Solo necesitaba hacer esto, pero pensé que la solución de Steven sería lenta. Esto debería usar gráficos HW. Crea una categoría en UIImage:

- (UIImage *)imageByApplyingAlpha:(CGFloat) alpha {
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);

    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGRect area = CGRectMake(0, 0, self.size.width, self.size.height);

    CGContextScaleCTM(ctx, 1, -1);
    CGContextTranslateCTM(ctx, 0, -area.size.height);

    CGContextSetBlendMode(ctx, kCGBlendModeMultiply);

    CGContextSetAlpha(ctx, alpha);

    CGContextDrawImage(ctx, area, self.CGImage);

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return newImage;
}
Nick H247
fuente
3
Ni siquiera puedo recordar por qué necesitaba esto :)
Marty
¡Gran solución! ¡Gracias Nick!
Christopher
1
Solo asegúrese de llamar a UIGraphicsBeginImageContextWithOptions en el hilo principal porque la representación en segundo plano será impredecible.
Steven Veltema
1
Según Apple, puede llamar a UIGraphicsBeginImageContextWithOptions en cualquier hilo desde iOS 4 y posteriores.
Hormigas
6
Funciona muy bien, muchas gracias. Para otros novatos en la logística en torno al desarrollo de iOS, estos son los pasos para crear una categoría para UIImage. 1. Haga clic con el botón derecho en el director de su proyecto y seleccione Nuevo archivo. 2. En la pantalla que aparece, seleccione el tipo de archivo de categoría Objective-C. 3. Agregue el código de la respuesta en el archivo .my una declaración para el método en el archivo .h. 4. En el archivo que usa la imagen para ser transparente, #importe el archivo. 5. Utilice el método imageByApplyingAlpha en una instancia de UIImage.
Danny
79

Establezca la opacidad de la vista en la que se muestra.

UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageWithName:@"SomeName.png"]];
imageView.alpha = 0.5; //Alpha runs from 0.0 to 1.0

Use esto en una animación. Puede cambiar el alfa en una animación por una duración.

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
//Set alpha
[UIView commitAnimations];
Alfombrillas Stijlaart
fuente
sí, estaba pensando que podría tener que hacerlo así con un temporizador para cambiar la opacidad constantemente, solo pensé que sería mucho más fácil tener una matriz para la propiedad de matriz de imágenes de animación para que se animara por sí sola.
Marty
Puede animarlo 'dentro' y 'fuera' como un latido con el delegado de animación. No uses un temporizador, la animación cambiará el alfa sin problemas. Buena suerte.
Mats Stijlaart
3
Esto solo funciona si el desarrollador está usando un UIImageView. La pregunta dice claramente que ese no es el caso.
Raul Huerta
1
Esto funciona con un UIImage presentado en un CALayer, solo usted establece layer.opacity sin tener que modificar la imagen en absoluto. ¡Gracias Mats!
Chris
¡Excelente! Funciona UIButton, exactamente lo que necesitaba.
NecipAllef
52

Basado en la respuesta de Alexey Ishkov, pero en Swift

Usé una extensión de la clase UIImage.

Rápido 2:

Extensión UIImage:

extension UIImage {
    func imageWithAlpha(alpha: CGFloat) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        drawAtPoint(CGPointZero, blendMode: .Normal, alpha: alpha)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
}

Usar:

let image = UIImage(named: "my_image")
let transparentImage = image.imageWithAlpha(0.5)

Rápido 3/4/5:

Tenga en cuenta que esta implementación devuelve un UIImage opcional. Esto se debe a que en Swift 3 UIGraphicsGetImageFromCurrentImageContextahora devuelve una opción. Este valor podría ser nulo si el contexto es nulo o con lo que no se creó UIGraphicsBeginImageContext.

Extensión UIImage:

extension UIImage {
    func image(alpha: CGFloat) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        draw(at: .zero, blendMode: .normal, alpha: alpha)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
}

Usar:

let image = UIImage(named: "my_image")
let transparentImage = image?.image(alpha: 0.5)
Devin B
fuente
Prefiero esta Swift 3versión.
AechoLiu
Gracias. Funciona igual en Swift 4, actualicé la respuesta para reflejar esto.
zeeshan
Bravo señor, bravo
Ryan Brodie
17

hay una solución mucho más fácil:

- (UIImage *)tranlucentWithAlpha:(CGFloat)alpha
{
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    [self drawAtPoint:CGPointZero blendMode:kCGBlendModeNormal alpha:alpha];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
Alexey Ishkov
fuente
1
Probablemente debería haber sido la respuesta aceptada. La forma más rápida / eficiente de obtener el resultado
Will Von Ullrich
4

Me doy cuenta de que es bastante tarde, pero necesitaba algo como esto, así que preparé un método rápido y sucio para hacerlo.

+ (UIImage *) image:(UIImage *)image withAlpha:(CGFloat)alpha{

    // Create a pixel buffer in an easy to use format
    CGImageRef imageRef = [image CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    UInt8 * m_PixelBuf = malloc(sizeof(UInt8) * height * width * 4);

    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(m_PixelBuf, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);

    //alter the alpha
    int length = height * width * 4;
    for (int i=0; i<length; i+=4)
    {
        m_PixelBuf[i+3] =  255*alpha;
    }


    //create a new image
    CGContextRef ctx = CGBitmapContextCreate(m_PixelBuf, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGImageRef newImgRef = CGBitmapContextCreateImage(ctx);  
    CGColorSpaceRelease(colorSpace);
    CGContextRelease(ctx);  
    free(m_PixelBuf);

    UIImage *finalImage = [UIImage imageWithCGImage:newImgRef];
    CGImageRelease(newImgRef);  

    return finalImage;
}
Steven Veltema
fuente
2
Mejor nombre seríasetImage:withAlpha:
Alexander
8
set generalmente se refiere a propiedades, cambiando de alguna manera el estado del receptor. ¿Sería mejor nombrarlo image:withAlpha:?
Jonathan.
2
Si. También se aplica el conjunto de llamadas configurando el mismo objeto pasado, en lugar de devolver una nueva imagen.
sistema
4

¡Hola, gracias del usuario de Xamarin! :) Aquí va traducido a c #

//***************************************************************************
public static class ImageExtensions
//***************************************************************************
{
    //-------------------------------------------------------------
    public static UIImage WithAlpha(this UIImage image, float alpha)  
    //-------------------------------------------------------------
        {
        UIGraphics.BeginImageContextWithOptions(image.Size,false,image.CurrentScale);
        image.Draw(CGPoint.Empty, CGBlendMode.Normal, alpha);
        var newImage = UIGraphics.GetImageFromCurrentImageContext();
        UIGraphics.EndImageContext();
        return newImage;
        }

}

Ejemplo de uso:

var MySupaImage = UIImage.FromBundle("opaquestuff.png").WithAlpha(0.15f);
Nick Kovalsky
fuente
1

mismo resultado que otros, estilo diferente:

extension UIImage {

    func withAlpha(_ alpha: CGFloat) -> UIImage {
        return UIGraphicsImageRenderer(size: size).image { _ in
            draw(at: .zero, blendMode: .normal, alpha: alpha)
        }
    }

}
Jarra Devin
fuente
1

Rápido 5:

extension UIImage {
  func withAlphaComponent(_ alpha: CGFloat) -> UIImage? {
    UIGraphicsBeginImageContextWithOptions(size, false, scale)
    defer { UIGraphicsEndImageContext() }

    draw(at: .zero, blendMode: .normal, alpha: alpha)
    return UIGraphicsGetImageFromCurrentImageContext()
  }
}
Vadoff
fuente
0

Si está experimentando con el renderizado de Metal y está extrayendo la CGImage generada por imageByApplyingAlpha en la primera respuesta, puede terminar con un renderizado de Metal que sea más grande de lo esperado. Mientras experimenta con Metal, es posible que desee cambiar una línea de código en imageByApplyingAlpha:

    UIGraphicsBeginImageContextWithOptions (self.size, NO, 1.0f);
//  UIGraphicsBeginImageContextWithOptions (self.size, NO, 0.0f);

Si está utilizando un dispositivo con un factor de escala de 3.0, como el iPhone 11 Pro Max, el factor de escala 0.0 que se muestra arriba le dará una CGImage que es tres veces más grande de lo que espera. Cambiar el factor de escala a 1.0 debería evitar cualquier escala.

Con suerte, esta respuesta evitará muchas molestias a los principiantes.

rusos
fuente